12

Quindi, sono totalmente nuovo a OCaml e mi sto muovendo abbastanza lentamente per implementare le mie prime funzioni. Una cosa che riesco a capire è quando usare le abilità di pattern corrispondenti comeOCaml: Pattern matching vs If/else statements

let foo = 
[] -> true 
| _ -> false;; 

vs utilizzando la struttura if altro come

let foo a = 
if a = [] then true else false;; 

Quando devo utilizzare ciascuno?

+1

La risposta accettata di seguito sembra buona nella maggior parte dei casi. Tuttavia, come nella maggior parte dei linguaggi di programmazione (tutti?), Raramente è una buona idea dire qualcosa sulla falsariga di 'if condition then true else false'; puoi invece usare solo 'condizione'. In questo caso, puoi dire "lascia foo a = (a = [])" ed evitare entrambe le corrispondenze di pattern e if. –

risposta

15

Non credo che ci sia una risposta chiara a questa domanda. In primo luogo, il caso evidente di pattern matching è quando è necessario distruggendo, ad esempio:

let rec sum = function 
    | [] -> 0 
    | head :: tail -> head + sum tail;; 

Un altro caso evidente è quando si sta definendo una funzione ricorsiva, pattern matching rendere la condizione bordo più chiaro, ad esempio:

let rec factorial = function 
    | 0 -> 1 
    | n -> n * factorial(n - 1);; 

invece di:

let rec factorial = function n -> 
    if n = 0 then 
    1 
    else 
    n * factorial(n-1);; 

che potrebbe non essere un grande esempio, basta usare la vostra immaginazione per capire le condizioni dei bordi più complesse! ;-)

In termini di regolari (ad esempio C Come) lingue, potrei dire che si dovrebbe usare il pattern matching, invece di switch/case e if al posto del l'operatore ternario. Per tutto il resto è una specie di zona grigia, ma la combinazione di modelli è solitamente preferita nella famiglia di lingue ML.

+0

+1. Lo avrei aumentato con un'altra regola empirica. Se esegui la corrispondenza del modello con 'true' e' false', considera un 'if'. Se il tuo 'if' usa una funzione per esprimere un pattern match chiaro, considera' match'. Inoltre 'match' può evitare chiamate di funzione, a differenza di molte espressioni' if'. –

+0

Questo è un buon punto! –

2

Per quanto ne so la differenza significativa è che l'espressione delle guardie nell'istruzione match è un pattern che significa che puoi fare cose che ti permettono di separare la forma (destruct) dall'espressione abbinata, come ha mostrato Nicolas nella sua risposta. L'altra implicazione di questo è che il codice come questo:

let s = 1 in 
    let x = 2 in 
    match s with 
    x -> Printf.printf "x does not equal s!!\n" x 
    | _ -> Printf.printf "x = %d\n" x; 

non farà quello che ci si aspetta. Questo perché x nell'istruzione della partita non si riferisce allo x nella dichiarazione let sopra ma è un nome del modello. In casi come questi è necessario utilizzare le dichiarazioni if.

0

La corrispondenza del modello consente la decostruzione di tipi di dati composti e, in generale, la possibilità di associare il modello all'interno di una data struttura dati, piuttosto che utilizzare condizionali come la struttura if .. then. La corrispondenza di modelli può anche essere utilizzata per i casi di uguaglianza booleana usando il costrutto di tipo | x quando (r == n). Dovrei anche aggiungere la corrispondenza del modello è molto più efficiente di se ... quindi .. costruisce, quindi usalo liberamente!

+0

FWIW, non penso 'match x con 3 -> f x | _ -> g x' sarà più efficiente di 'if x = 3 then f x else g x'. Mi concentrerei personalmente sulla chiarezza del codice. –

+0

In tal caso, sarei d'accordo. Ma considera il caso, 'match x con | 0 -> 1 | 1 -> 2 | 2 -> 3 | _ -> x + 1' vs 'if x = 0 then 1 else se x = 1 then 2 else se x = 2 then 3 else x + 1'. Se si dovessero confrontare queste funzioni, la corrispondenza del modello sarebbe significativamente più efficiente. A mano a mano che i casi aumentano (specialmente quando accelerati con ricorsione), le differenze di rendimento possono aumentare di ordini di grandezza. –