F # explizite Übereinstimmung mit Funktionssyntax

86

Entschuldigung für den vagen Titel, aber ein Teil dieser Frage ist, wie diese beiden Syntaxstile heißen:

let foo1 x = 
    match x with
    | 1 -> "one"
    | _ -> "not one"

let foo2 = function 
    | 1 -> "one" 
    | _ -> "not one"

Der andere Teil ist, welchen Unterschied es zwischen den beiden gibt und wann ich den einen oder anderen verwenden möchte?

Benjol
quelle
2
Danke dir. Ich finde diese Frage sehr wertvoll. Ich beschäftige mich eingehender mit F #, nachdem ich gerade einige neue Texte erworben habe und das Funktionsschlüsselwort gerade aufgetaucht ist.
Octopusgrabbus

Antworten:

54

Die Übereinstimmungsversion wird als "Mustervergleichsausdruck" bezeichnet. Die Funktionsversion wird als "Mustervergleichsfunktion" bezeichnet. Gefunden in Abschnitt 6.6.4 der Spezifikation .

Die Verwendung übereinander ist eine Frage des Stils. Ich bevorzuge die Verwendung der Funktionsversion nur, wenn ich eine Funktion definieren muss, die nur eine Übereinstimmungsanweisung ist.

gradbot
quelle
Danke dir. Obwohl die funktionale Programmierung mit F # besagt, dass die Verwendung des Funktionsschlüsselworts anzeigt, dass es sich um eine Mustervergleichsfunktion handelt, klären diese Antwort und das OP einen Moment, in dem das Gehirn feststeckt.
Octopusgrabbus
Die Verbindung scheint unterbrochen zu sein.
MattMS
81

Der Vorteil der zweiten Syntax ist, dass sie bei Verwendung in einem Lambda etwas knapper und lesbarer sein kann.

List.map (fun x -> match x with | 1 -> "one" | _ -> "not one") [0;1;2;3;1]

vs.

List.map (function 1 -> "one" | _ -> "not one") [0;1;2;3;1]
Stringer
quelle
23

Die Funktionsversion ist eine Kurzform für die vollständige Übereinstimmungssyntax in dem speziellen Fall, in dem die Übereinstimmungsanweisung die gesamte Funktion ist und die Funktion nur ein einziges Argument hat (Tupel zählen als eins). Wenn Sie zwei Argumente haben möchten, müssen Sie die vollständige Übereinstimmungssyntax * verwenden. Sie können dies an den Typen der folgenden beiden Funktionen erkennen.

//val match_test : string -> string -> string
let match_test x y = match x, y with
                        | "A", _ -> "Hello A"
                        | _, "B" -> "Hello B"
                        | _ -> "Hello ??"

//val function_test : string * string -> string                   
let function_test = function
                        | "A", _ -> "Hello A"
                        | _, "B" -> "Hello B"
                        | _ -> "Hello ??"

Wie Sie sehen können, verwendet die Match-Version zwei separate Argumente, während die Funktionsversion ein einzelnes Tupel-Argument verwendet. Ich verwende die Funktionsversion für die meisten Funktionen mit einzelnen Argumenten, da ich finde, dass die Funktionssyntax sauberer aussieht.

* Wenn Sie wirklich wollten, können Sie die Funktionsversion mit der richtigen Typensignatur erhalten, aber sie sieht meiner Meinung nach ziemlich hässlich aus - siehe Beispiel unten.

//val function_match_equivalent : string -> string -> string
let function_match_equivalent x y = (x, y) |> function
                                                | "A", _ -> "Hello A"
                                                | _, "B" -> "Hello B"
                                                | _ -> "Hello ??"
Joshua
quelle
12

In Ihrem Fall machen sie dasselbe - das functionSchlüsselwort verhält sich wie eine Kombination des funSchlüsselworts (um ein anonymes Lambda zu erzeugen) gefolgt vom matchSchlüsselwort.

Technisch gesehen sind diese beiden also identisch, mit dem Zusatz fun:

let foo1 = fun x ->
    match x with
    | 1 -> "one"
    | _ -> "not one"

let foo2 = function
    | 1 -> "one"
    | _ -> "not one"
Tim Robinson
quelle
1
Ist es nicht tatsächlich umgekehrt - dh funtechnisch definiert in Bezug auf function | _ -> ...?
Pavel Minaev
1
Um genau zu sein, fun x y -> ...wäre fun x -> fun y -> ...und fun x -> ...wäre dann function | x -> .... Aus diesem Grund können Sie Musterabgleiche durchführen, funz fun (x::xs) -> ....
Pavel Minaev
10

Der Vollständigkeit halber bin ich gerade auf Seite 321 von Expert FSharp gekommen :

"Hinweis: Listing 12.2 verwendet die Ausdrucksform function pattern-rules -> expression. Dies entspricht (fun x -> match x with pattern-rules -> expression)der Definition von Funktionen, die direkt über diskriminierte Gewerkschaften arbeiten , und ist besonders praktisch."

Benjol
quelle
6

Die Funktion erlaubt nur ein Argument, aber den Mustervergleich, während Spaß die allgemeinere und flexiblere Art ist, eine Funktion zu definieren. Schauen Sie hier: http://caml.inria.fr/pub/docs/manual-ocaml/expr.html

Kamaci
quelle
Warum sagst du nur 1 Argument statt nur das letzte Argument? Es ist möglich, mehr als ein Argument zu haben und "Funktion" zu verwenden. Ist dies eine Funktionsinterpretation höherer Ordnung?
Symbiont
4

Die beiden Syntaxen sind äquivalent. Die meisten Programmierer wählen den einen oder anderen und verwenden ihn dann konsequent.

Die erste Syntax bleibt besser lesbar, wenn die Funktion mehrere Argumente akzeptiert, bevor sie mit der Arbeit beginnt.

Pascal Cuoq
quelle
2

Dies ist eine alte Frage, aber ich werde meine $ 0,02 werfen.

Im Allgemeinen gefällt mir die matchVersion besser, da ich aus der Python-Welt komme, in der "explizit besser als implizit ist".

Wenn Typinformationen zum Parameter benötigt werden, kann die functionVersion natürlich nicht verwendet werden.

OTOH Ich mag das Argument von, Stringeralso werde ich anfangen, es functionin einfachen Lambdas zu verwenden.

Soldalma
quelle