Question

Je viens de remarquer que F # me permet d’utiliser les liaisons let avec des littéraux et d’autres modèles comme suit:

let fib 0 = 1
let exists item [] = false
let car (hd :: tl) = hd
let cdr (hd :: tl) = tl

F # interprète correctement ces fonctions comme une sorte de correspondance de modèle, car il me donne les avertissements suivants:

  

Avertissement 1 Correspondances incomplètes   sur cette expression. Par exemple, le   la valeur '1' ne sera pas   apparié

     

Avertissement 2 Correspondances incomplètes   sur cette expression. Par exemple, le   la valeur '[_]' ne sera pas   apparié

     

etc.

Ces fonctions fonctionnent comme prévu, mais je souhaite définir une fonction dans ce style avec des correspondances de modèle complètes, mais je ne trouve rien sur cette syntaxe de correspondance de modèle alternative dans le manuel F #.

Je sais que je peux utiliser laisser quoi que soit = ??fonction ... et laisser faire quoi que ce soit x = faire correspondre x avec ... pour obtenir les résultats souhaités, mais je Je viens de découvrir encore une autre syntaxe pour la correspondance des motifs et ça me tracassera pour toujours si je ne comprends pas comment l'utiliser.

Comment puis-je écrire des fonctions en utilisant la syntaxe de correspondance de modèle alternative ci-dessus?

Était-ce utile?

La solution

JaredPar a raison, F # n'a pas la forme syntaxique que Haskell a ici.

La forme F # est principalement utile pour casser des unions discriminées ouvertes par cas unique ou pour définir des fonctions avec des correspondances incomplètes (comme votre exemple "voiture" qui échoue dans la liste vide). C’est simplement une conséquence du fait que pratiquement toute la corrélation de noms dans la langue se fait via des modèles; cette forme syntaxique (définir une fonction en utilisant des modèles sur des arguments) n’est pas souvent très utile en pratique, pour la raison exacte que vous avez décrite.

Je pense que Haskell a fait un certain nombre de choses mieux que ML en ce qui concerne les formes syntaxiques, mais les racines de F # se trouvent dans ML. L'avantage est qu'un bon sous-ensemble de F # compile de manière croisée avec OCaml (ce qui a contribué à amorcer le langage F # et la communauté des utilisateurs); L'inconvénient est que F # est «bloqué» avec quelques bits de syntaxe laide / limitée.

Autres conseils

D'après ce que je sais, il n'y a aucun moyen dans F # de déclarer plusieurs liaisons let avec le même nom et des signatures de correspondance de modèle différentes. Je crois que la construction la plus proche de ce que vous recherchez est une expression de règles de fonction.

Prenez cet exemple pour la voiture

let car = function
    | hd::tl -> hd
    | [] -> failwith "empty list"

Apparemment, la correspondance de motif de F # est bien plus puissante que celle que nous utilisons dans le développement courant.

Tout d'abord, vous pouvez lier plusieurs valeurs à la fois. En règle générale, vous le ferez avec List.partition :

let data = [7;0;0;0;1;0;1;1;1;1;0;0;1;1;0]
let ones, others = data |> List.partition ((=) 1) // bind two values

Remarque: vous pouvez associer plusieurs identificateurs à la même valeur:

let (a & b) = 42 // a = 42; b = 42

Commençons par une simple liaison let par souci de simplicité.

let hd::tl = data
  

avertissement FS0025 : Le modèle incomplet correspond à cette expression. Par exemple, la valeur "[]" peut indiquer un cas non couvert par le ou les modèles.

Pour atténuer cela, nous devons ajouter un autre cas pour la liste vide:

let (hd::tl) | [] = data
  

erreur FS0018 : les deux côtés de ce modèle "ou" lient différents ensembles de variables

Et c'est vrai; en cas de liste vide, hd et tl restent non liés. Il est facile de lier tl avec la même liste vide:

let (hd::tl) | ([] as tl) = data

Cependant, l'erreur erreur FS0018 ne disparaît pas. En effet, nous devons également fournir quelques "paramètres par défaut". valeur pour hd .
Le sale tour suivant fera ceci.

let (hd::tl, _) | ([] as tl , hd) = data, 42

La ligne ci-dessus liera hd à la tête de data , au cas où la liste ne serait pas vide, ou avec l'extra valeur fournie dans la deuxième valeur du tuple .

Remarque : je n'ai pas trouvé le moyen d'intégrer 42 dans la construction let .

Enfin, la même chose pour la voiture :

let car ((hd::tl, _) | ([] as tl, hd)) = hd
let foo = car(data, 42) // foo = 7
let bar = car([], 42)   // bar = 42
  

Comment puis-je écrire des fonctions en utilisant la syntaxe de correspondance de modèle alternative indiquée ci-dessus?

Comme vous l’avez fait, mais seulement quand un modèle est exhaustif. Des exemples évidents où cela est utile comprennent les n-uplets et les enregistrements, ainsi que les unions à cas unique et les schémas actifs.

Vous utilisez cette fonctionnalité de langue chaque fois que vous le faites:

let f(a, b) = ...

Donc, ceci se généralise à:

let f(a, (b, c)) = ...

Vous pouvez même l'utiliser pour choisir entre une valeur par défaut ou Une valeur :

let def(x, None | _, Some x) = x

BTW, le style que vous suggérez a été utilisé dans SML avant Haskell et SML est un ML, donc cela n’a évidemment rien à voir avec Haskell vs ML. En fait, je préfère le style OCaml / F # car il est moins répétitif:

fun descriptiveFunctionName [] = true
fun descriptiveFunctionName (_::_) = false

vs

let descriptiveFunctionName = function
  | [] -> true
  | _::_ -> false

C’est mieux pour les codes non académiques où il ya une réelle valeur à utiliser des identifiants auto-documentés.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top