2012-11-27 5 views
7

Ich habe ein Dictionary über die ich thusly zunächst iterativ:Der Versuch, F # aktive Muster zu verstehen, warum ich das tun kann:

myDictionary |> Seq.iter (fun kvp -> doSomething kvp.Key kvp.Value)

Später entdeckte ich, dass ich die Verwendung des KeyValue aktiven Muster machen könnte dies und tun:

myDictionary |> Seq.iter (fun (KeyValue (k, v)) -> doSomething k v)

zu wissen, dass aktive Muster nicht irgendeine Form von Präprozessordirektive sind, wie bin ich in der Lage, diezu ersetzenArgument im Lambda für eine Funktion, die es zerlegt?

Antwort

14

Funktionen Argumente werden immer mit Pattern Matching destrukturiert. Zum Beispiel:

let getSingleton = fun [x] -> x 
let getFirst = fun (a,b) -> a 
let failIfNotOne = fun 1 ->() 
let failIfNeitherOne = fun (x,1 | 1,x) ->() 

Semantisch fun < pat>-> < body> entspricht in etwa

fun x ->
match x with
| < pat>-> < body>
| _ -> raise MatchFailureException(...)

+0

Danke, das ist ein Augenöffner, kvb! Ich werde dieses letzte Beispiel unbedingt im Hinterkopf behalten müssen. – MiloDC

5

ich denke, die Antwort von @kvb deckt genug deta ab Deshalb können Sie Muster in den Argumenten fun verwenden. Dies ist keine Ad-hoc-Funktion - in F # können Sie Muster überall dort verwenden, wo Sie eine Variable binden können. Um nur einige der Beispiele von @kvb in anderen Kontexten zu zeigen:

// When declaring normal functions  
let foo [it] = it // Return the value from a singleton list 
let fst (a, b) = a // Return first element of a pair 

// When assigning value to a pattern using let 
let [it] = list 
let (a, b) = pair 

Ebenso können Sie Muster verwenden, wenn fun zu schreiben. Das Konstrukt match ist etwas leistungsfähiger, weil Sie mehrere Klauseln angeben können.

Jetzt sind aktive Muster nicht wirklich so magisch. Sie sind nur normale Funktionen mit speziellen Namen. Der Compiler sucht nach aktiven Mustern im Bereich, wenn ein benanntes Muster gefunden wird. Zum Beispiel kann das Muster, das Sie verwenden sind, ist nur eine Funktion:

val (|KeyValue|) : KeyValuePair<'a,'b> -> 'a * 'b 

Das Muster macht aus einem KevValuePair Objekt in einen normalen F # Tupel, die dann von einem verschachtelten Muster angepasst ist (k, v) (die das erste Element k zuweist und der zweite zu v). Der Compiler übersetzt im Wesentlichen Ihren Code zu:

myDictionary |> Seq.iter (fun _arg0 -> 
    let _arg1 = (|KeyValue|) _arg0 
    let (k, v) = _arg1 
    doSomething k v) 
+4

Nicht ganz überall ... Zumindest 'use' Bindings und der 'this'-Bezeichner in Member-Deklarationen sind leider eher auf die Verwendung von richtigen Bezeichnern als auf Muster beschränkt. – kvb

+4

@ kvb Wahr und wahr. Auch nicht für 'as self' in implicit-constructor-Klassen. Ich glaube, das sind die einzigen drei Fälle, in denen der Name tatsächlich eine Bedeutung hat. –

+1

@ kvb Das ist ein exzellenter Punkt, ach ja, der Konflikt zwischen Theorie und Praxis schlägt wieder zu :-) –

Verwandte Themen