A common surprise pour les programmeurs début F # est le fait que ce qui suit est une correspondance incomplète:correspondance incomplète modèle lorsque deux modèles partagent une `when` clause
let x, y = 5, 10
match something with
| _ when x < y -> "Less than"
| _ when x = y -> "Equal"
| _ when x > y -> "Greater than"
Mais je rencontrais une situation qui m'a surpris. Voici un petit morceau de code de l'échantillon pour le démontrer:
type Tree =
| Leaf of int
| Branch of Tree list
let sapling = Branch [Leaf 1] // Small tree with one leaf
let twoLeafTree = Branch [Leaf 1; Leaf 2]
let describe saplingsGetSpecialTreatment tree =
match tree with
| Leaf n
| Branch [Leaf n] when saplingsGetSpecialTreatment ->
sprintf "Either a leaf or a sapling containing %d" n
| Branch subTree ->
sprintf "Normal tree with sub-tree %A" subTree
describe true sapling // Result: "Either a leaf or a sapling containing 1"
describe false sapling // Result: "Normal tree with sub-tree [Leaf 1]"
describe true twoLeafTree // Result: "Normal tree with sub-tree [Leaf 1; Leaf 2]"
describe false twoLeafTree // Result: "Normal tree with sub-tree [Leaf 1; Leaf 2]"
Cette version de la fonction describe
produit le « modèle incomplet correspond à cette expression » avertissement, même si le match de modèle est, en fait, complet. Il n'y a pas d'arbres possibles qui ne seront pas abondés par ce match de modèle, comme on peut le voir par enlever la branche spécifique du match qui avait une expression when
en elle:
let describe tree =
match tree with
| Leaf n -> sprintf "Leaf containing %d" n
| Branch subTree ->
sprintf "Normal tree with sub-tree %A" subTree
Cette version de describe
renvoie la Chaîne "Arbre normal" pour les arbres sapling
et twoLeafTree
.
Dans le cas où l'expression match
ne contient que when
expressions (comme le premier exemple où x
et y
sont comparés), il est raisonnable que le compilateur F # peut ne pas être en mesure de dire si le match sera terminé. Après tout, x
et y
pourrait être types avec un « bizarre » la mise en œuvre de comparaison et de l'égalité où aucune de ces trois branches sont vraies. *
Mais dans des cas comme ma fonction describe
, pourquoi ne pas le F # compilateur regardez le motif, dites "Si toutes les expressions when
évalués à false
, il y aurait toujours une correspondance complète" et ignorer l'avertissement "incomplète motif correspond"? Y a-t-il une raison spécifique pour que cet avertissement apparaisse ici, ou est-ce juste un cas où le compilateur F # est juste un peu simpliste ici et donne un avertissement faussement positif parce que son code n'était pas assez sophistiqué?
* En fait, il est possible de définir x
et y
à des valeurs telles que x < y
, x = y
et x > y
sont tous faux, sans jamais marcher en dehors des limites « normales » du système standard de type .Net. En tant que question spéciale/puzzle, quelles sont ces valeurs de x
et y
? Aucun type personnalisé nécessaire pour répondre à ce casse-tête; tout ce dont vous avez besoin est de types fournis en standard .Net.
Pour clarifier les choses, par "énuméré juste avant", vous voulez dire sans intervention '- > ' – bergey
Oui, c'est ce que je veux dire. –
Mon code original avait en fait le cas 'Branch' avec un traitement spécial * en premier * et le cas' Leaf n' en second. Le cas 'Branch' avait une condition' when', mais omettait un '->' car je voulais aussi faire correspondre le cas 'Leaf'. Et ce que j'ai eu, c'est l'erreur "Symbole inattendu" '' '" dans la correspondance de pattern, attendu '' -> '' ou un autre jeton. " À l'époque, je ne comprenais pas pourquoi cela avait échoué, mais le cas de 'Leaf' fonctionnait; Maintenant que je sais que les clauses 'when' s'appliquent à * tous * les patterns de ce" groupe "particulier (tous les patterns qui partagent un' -> '), je comprends l'erreur de syntaxe. Merci! – rmunn