F # syntaxe explicite vs fonction

87

Désolé pour le titre vague, mais une partie de cette question est de savoir comment s'appellent ces deux styles de syntaxe:

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

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

L'autre partie est quelle différence il y a entre les deux, et quand je voudrais utiliser l'un ou l'autre?

Benjol
la source

Réponses:

56

La version de correspondance est appelée "expression de correspondance de modèle". La version de la fonction est appelée "fonction de correspondance de modèle". Trouvé dans la section 6.6.4 de la spécification .

Utiliser l'un sur l'autre est une question de style. Je préfère n'utiliser la version de fonction que lorsque j'ai besoin de définir une fonction qui n'est qu'une instruction de correspondance.

gradbot
la source
Merci. Bien que la programmation fonctionnelle utilisant F # indique que l'utilisation du mot-clé de fonction indique qu'il s'agit d'une fonction de correspondance de modèle, cette réponse et l'OP clarifient un moment de blocage cérébral.
octopusgrabbus
Le lien semble rompu.
MattMS
83

L'avantage de la deuxième syntaxe est que lorsqu'elle est utilisée dans un lambda, elle pourrait être un peu plus laconique et lisible.

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

contre

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

La version de la fonction est un raccourci pour la syntaxe de correspondance complète dans le cas spécial où l'instruction de correspondance est la fonction entière et la fonction n'a qu'un seul argument (les tuples comptent pour un). Si vous souhaitez avoir deux arguments, vous devez utiliser la syntaxe de correspondance complète *. Vous pouvez le voir dans les types des deux fonctions suivantes.

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

Comme vous pouvez le voir, la version de correspondance prend deux arguments distincts, tandis que la version de la fonction prend un seul argument multiplié. J'utilise la version de fonction pour la plupart des fonctions à argument unique car je trouve que la syntaxe de la fonction semble plus propre.

* Si vous le vouliez vraiment, vous pouvez obtenir la version de la fonction pour avoir la bonne signature de type, mais cela semble assez moche à mon avis - voir l'exemple ci-dessous.

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

Ils font la même chose dans votre cas - le functionmot - clé agit comme une combinaison du funmot - clé (pour produire un lambda anonyme) suivi du matchmot - clé.

Donc techniquement, ces deux sont les mêmes, avec l'ajout d'un fun:

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

let foo2 = function
    | 1 -> "one"
    | _ -> "not one"
Tim Robinson
la source
1
N'est-ce pas réellement l'inverse - c'est-à-dire funest défini techniquement en termes de function | _ -> ...?
Pavel Minaev
1
Pour être précis, ce fun x y -> ...serait fun x -> fun y -> ..., puis ce fun x -> ...serait function | x -> .... C'est pourquoi vous pouvez faire une correspondance de motifs dans fun- par exemple fun (x::xs) -> ....
Pavel Minaev
10

Pour être complet, je viens de passer à la page 321 d' Expert FSharp :

"Notez que le Listing 12-2 utilise la forme d'expression function pattern-rules -> expression. Ceci est équivalent (fun x -> match x with pattern-rules -> expression)et est particulièrement pratique comme moyen de définir des fonctions travaillant directement sur des unions discriminées."

Benjol
la source
6

function n'autorise qu'un seul argument mais permet la correspondance de modèles, tandis que le fun est la manière la plus générale et la plus flexible de définir une fonction. Jetez un œil ici: http://caml.inria.fr/pub/docs/manual-ocaml/expr.html

Kamaci
la source
pourquoi dites-vous seulement 1 argument au lieu du seul dernier argument? il est possible d'avoir plus d'un argument et d'utiliser "fonction". est-ce une interprétation de fonction d'ordre supérieur?
symbiont
4

Les deux syntaxes sont équivalentes. La plupart des programmeurs choisissent l'un ou l'autre et l'utilisent ensuite de manière cohérente.

La première syntaxe reste plus lisible lorsque la fonction accepte plusieurs arguments avant de commencer à travailler.

Pascal Cuoq
la source
2

C'est une vieille question mais je vais jeter mon 0,02 $.

En général, j'aime mieux la matchversion puisque je viens du monde Python où "explicite vaut mieux qu'implicite".

Bien sûr, si des informations de type sur le paramètre sont nécessaires, la functionversion ne peut pas être utilisée.

OTOH J'aime l'argument avancé par Stringerdonc je vais commencer à l'utiliser functiondans de simples lambdas.

Soldalma
la source