2010-05-17 17 views
11

In "Programmazione F #" Mi sono imbattuto in un pattern-matching come questo (ho semplificato un po '):intesa pattern matching con operatore cons

let rec len list = 
    match list with 
    | [] -> 0 
    | [_] -> 1 
    | head :: tail -> 1 + len tail;; 

In pratica, ho capito che l'ultima partita riconosce la testa e coda della lista. Concettualmente, non capisco perché funzioni. Per quanto ne so, :: è l'operatore cons, che aggiunge un valore in testa di una lista, ma non mi sembra che venga usato come operatore qui. Dovrei capire questo come una "sintassi speciale" per le liste, dove: viene interpretato come un operatore o un "modello di corrispondenza" a seconda del contesto? Oppure la stessa idea può essere estesa per tipi diversi dagli elenchi, con altri operatori?

risposta

10

Oltre alla risposta di Brian, ci sono alcuni punti che vale la pena notare. La sintassi h::t può essere utilizzato sia come operatore e come un modello:

let l = 1::2::[]     // As an operator 
match l with x::xs -> 1 | [] -> 0 // As a pattern 

Ciò significa che è un costrutto speciale bit, perché altri operatori (per esempio +) non possono essere usati come motivi (per decomposizione il risultato torna agli argomenti dell'operatore) - ovviamente, per +, questo sarebbe ambiguo.

Inoltre, il motivo [_] è interessante, perché è un esempio di schema nidificato. Compone:

  • _ - Underscore modello, che corrisponde a qualsiasi valore e non si lega alcun simbolo
  • [ <pattern> ] - Single-elemento della lista modello, che corrisponde a una liste con elementi singoli e corrisponde l'elemento della lista con il nidificato <pattern>.

Si potrebbe anche scrivere match 1::[] with | [x] -> x che restituirebbe il valore del singolo elemento (in questo caso 1).

+0

Grazie, il vostro punto su :: essere un costrutto speciale è esattamente ciò di cui non ero chiara. Ho sperimentato cercando di utilizzare altri operatori in pattern-matching nello stesso modo, ma non aveva molto senso e non ho ottenuto nulla, ed è quello che mi ha fatto pensare ai contro. – Mathias

+1

Si noti che lo stesso vale per Tuples: è possibile utilizzare il modello (,) per creare e abbinare/disimballare tuple e anche per altri tipi (Some()/None) ecc. – Benjol

+0

Ecco un elenco di [tutti supportati tipi di motivo] (https://docs.microsoft.com/en-us/dotnet/articles/fsharp/language-reference/pattern-matching) con esempi. – JanDotNet

13

È una sintassi speciale per le liste. Si può pensare al tipo list come un'unione discriminata nel seguente modo:

type list<'T> =   // ' 
    | Nil 
    | Cons of 'T * list<'T> 

tranne che non c'è sintassi speciale che rende Nil essere [] e Cons(h,t) essere h::t. Quindi è solo la normale corrispondenza di modelli su un'unione discriminata. Questo aiuta?

(forse vedere anche this blog entry.)

+0

È molto utile, grazie! – Mathias

2

è usato come un formattatore o formalmente pattern, `lista' è abbinato ai tre modelli:

[] indica l'elenco è vuoto

[_] significa che la lista ha un elemento, dal momento che non ti interessa cosa sia l'elemento, quindi semplicemente metti _ lì, puoi anche usare [a].

head :: tail significa che l'elenco ha due parti: una testa e una coda.

È possibile visualizzare la corrispondenza del modello F # come una potente se poi altra struttura.