F # jawne dopasowanie do składni funkcji

87

Przepraszamy za niejasny tytuł, ale część tego pytania dotyczy nazw tych dwóch stylów składni:

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

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

Druga część to jaka jest różnica między tymi dwoma i kiedy chciałbym użyć jednego lub drugiego?

Benjol
źródło

Odpowiedzi:

56

Wersja dopasowania nazywana jest „wyrażeniem dopasowującym do wzorca”. Wersja funkcji jest nazywana „funkcją dopasowywania wzorców”. Znaleziono w sekcji 6.6.4 specyfikacji .

Używanie jednego nad drugim to kwestia stylu. Wolę używać wersji funkcji tylko wtedy, gdy muszę zdefiniować funkcję, która jest tylko instrukcją dopasowania.

gradbot
źródło
Dziękuję Ci. Chociaż programowanie funkcjonalne przy użyciu F # mówi, że użycie słowa kluczowego function wskazuje, że jest to funkcja dopasowywania wzorców, ta odpowiedź i OP wyjaśniają moment utknięcia w mózgu.
octopusgrabbus
Wydaje się, że łącze jest uszkodzone.
MattMS,
83

Zaletą drugiej składni jest to, że gdy jest używany w lambdzie, może być nieco bardziej zwięzły i czytelny.

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]
Podłużnica
źródło
23

Wersja funkcji to krótka wskazówka dla pełnej składni dopasowania w specjalnym przypadku, gdy instrukcja match to cała funkcja, a funkcja ma tylko jeden argument (krotki liczą się jako jeden). Jeśli chcesz mieć dwa argumenty, musisz użyć pełnej składni dopasowania *. Można to zobaczyć w typach następujących dwóch funkcji.

//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 ??"

Jak widać, wersja dopasowania przyjmuje dwa oddzielne argumenty, podczas gdy wersja funkcji przyjmuje jeden argument krotny. Używam wersji funkcji dla większości funkcji jednoargumentowych, ponieważ uważam, że składnia funkcji wygląda na czystszą.

* Jeśli naprawdę chciałeś, możesz sprawić, by wersja funkcji miała odpowiedni podpis typu, ale moim zdaniem wygląda to dość brzydko - patrz przykład poniżej.

//val function_match_equivalent : string -> string -> string
let function_match_equivalent x y = (x, y) |> function
                                                | "A", _ -> "Hello A"
                                                | _, "B" -> "Hello B"
                                                | _ -> "Hello ??"
Joshua
źródło
12

Robią to samo w twoim przypadku - functionsłowo kluczowe działa jak kombinacja funsłowa kluczowego (w celu utworzenia anonimowej lambdy), po której następuje matchsłowo kluczowe.

Więc technicznie te dwa są takie same, z dodatkiem fun:

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

let foo2 = function
    | 1 -> "one"
    | _ -> "not one"
Tim Robinson
źródło
1
Czy nie jest na odwrót - tj. funJest technicznie zdefiniowane w kategoriach function | _ -> ...?
Pavel Minaev
1
Mówiąc konkretnie, fun x y -> ...będzie fun x -> fun y -> ..., a potem fun x -> ...będzie function | x -> .... Dlatego możesz dopasować wzorce w fun- np fun (x::xs) -> ....
Pavel Minaev
10

Ze względu na kompletność dotarłem do strony 321 Expert FSharp :

„Uwaga, listing 12-2 używa formy wyrażenia function pattern-rules -> expression. Jest to równoważne (fun x -> match x with pattern-rules -> expression)i szczególnie wygodne jako sposób definiowania funkcji działających bezpośrednio na związkach rozłącznych”.

Benjol
źródło
6

funkcja pozwala tylko na jeden argument, ale pozwala na dopasowanie do wzorca, podczas gdy zabawa jest bardziej ogólnym i elastycznym sposobem definiowania funkcji. Spójrz tutaj: http://caml.inria.fr/pub/docs/manual-ocaml/expr.html

kamaci
źródło
dlaczego mówisz tylko 1 argument zamiast tylko ostatniego argumentu? można mieć więcej niż 1 argument i użyć "funkcji". czy jest to interpretacja funkcji wyższego rzędu?
symbiont
4

Te dwie składnie są równoważne. Większość programistów wybiera jedną lub drugą, a następnie używa jej konsekwentnie.

Pierwsza składnia pozostaje bardziej czytelna, gdy funkcja przyjmuje kilka argumentów przed rozpoczęciem pracy.

Pascal Cuoq
źródło
2

To stare pytanie, ale rzucę 0,02 dolara.

Ogólnie bardziej podoba mi się matchwersja, ponieważ pochodzę ze świata Pythona, w którym „jawne jest lepsze niż niejawne”.

Oczywiście, jeśli potrzebne są informacje o typie parametru, functionnie można użyć wersji.

OTOH Podoba mi się argument przedstawiony przez, Stringerwięc zacznę używać functionw prostych lambdach.

Soldalma
źródło