61 votes

Quelle est la différence entre Pattern Matching et Guards?

Je suis très nouveau à Haskell et à la programmation fonctionnelle en général. Ma question est assez basique. Quelle est la différence entre le filtrage et des Gardes?

Fonction en utilisant l'appariement

check :: [a] -> String
check [] = "Empty"
check (x:xs) = "Contains Elements"

Fonction à l'aide de gardes

check_ :: [a] -> String
check_ lst
    | length lst < 1 = "Empty"
    | otherwise = "Contains elements"

Pour moi, il ressemble à la Correspondance de Modèle et les Gardes sont fondamentalement les mêmes. À la fois évaluer une condition, et si vrai exécutera l'expression accroché à elle. Ai-je raison de ma compréhension?

Dans cet exemple, je peux soit utiliser la correspondance de motif ou de gardes pour arriver au même résultat. Mais quelque chose me dit que je suis absent dehors sur quelque chose d'important ici. Pouvons-nous toujours remplacer l'une avec l'autre?

Quelqu'un pourrait-il donner des exemples où le pattern matching est préféré plus de gardes et vice-versa?

60voto

C. A. McCann Points 56834

En fait, ils sont fondamentalement très différents! Au moins en Haskell, en tout cas.

Les gardes sont à la fois plus simple et plus souple: Ils sont essentiellement juste une syntaxe spéciale, qui se traduit par une série de if/then expressions. Vous pouvez mettre arbitraire des expressions booléennes dans les gardes, mais ils ne font pas quelque chose que vous ne pouvais pas le faire avec une brosse if.

Modèle correspond à faire plusieurs autres choses: Ils sont la seule façon de déconstruire les données, et ils se lient identifiants au sein de leur champ d'application. Dans le même sens que les gardes sont équivalentes if expressions, le filtrage est équivalent à case expressions. Déclarations (soit au plus haut niveau, ou à quelque chose comme un let expression) sont aussi une forme de motif, à la "normale" définitions des matches avec le trivial, un identifiant unique.

Le motif correspond également tendance à être le moyen principal de trucs qui se passe réellement dans Haskell--la tentative de déconstruire des données dans un modèle est l'une des rares choses que les forces de l'évaluation.

Par ailleurs, vous pouvez effectivement faire un filtrage au niveau supérieur déclarations:

square = (^2)

(one:four:nine:_) = map square [1..]

C'est parfois utile pour un groupe de définitions connexes.

GHC également fournit la ViewPatterns extension qui combine à la fois; vous pouvez utiliser des fonctions arbitraires dans un contexte de liaison, puis correspondance de modèle sur le résultat. Ce n'est encore qu'sucre syntaxique pour les trucs habituels, bien sûr.


Comme pour la journée-à-jour de question de l'utiliser, voici quelques rough guides:

  • Certainement utiliser le pattern matching pour tout ce qui peut être associé directement à un ou deux constructeurs de profondeur, où vous n'avez pas vraiment sur le composé de données dans son ensemble, mais ne se soucient plus de la structure. L' @ syntaxe vous permet de lier l'ensemble de la structure à une variable tout en pattern matching sur elle, mais de faire trop de que, dans un modèle peut devenir moche et illisible rapidement.

  • Certainement utiliser gardes lorsque vous avez besoin de faire un choix basé sur des biens qui ne correspondent pas parfaitement à un modèle, par exemple en comparant les deux Int valeurs pour voir qui est plus grand.

  • Si vous avez besoin de seulement un couple de morceaux de données à partir du plus profond à l'intérieur d'une grande structure, en particulier si vous avez besoin d'utiliser l'ensemble de la structure, les gardes et les fonctions d'accesseur sont généralement plus lisible que certains monstrueux modèle plein de @ et _.

  • Si vous avez besoin de faire la même chose pour les valeurs représentées par des modèles différents, mais avec une pratique de prédicat à les classer, à l'aide d'un seul modèle générique avec un garde est habituellement plus lisible. Notez que si un ensemble de gardes est non-exhaustive, tout ce qui échoue tous les gardes de la liste déroulante pour le motif suivant (le cas échéant). Ainsi, vous pouvez combiner un modèle général avec certains filtres pour attraper des cas exceptionnels, puis faire un patron sur tout le reste pour obtenir plus de détails à vous soucier.

  • Certainement ne pas utiliser des protections pour les choses qui pourraient être trivialement vérifiée avec un motif. La vérification de vide listes est l'exemple classique, l'utilisation d'un motif pour cela.

  • En général, en cas de doute, il suffit de coller avec la correspondance de modèle par défaut, il est généralement plus agréable. Si un pattern commence à devenir vraiment laid ou compliquées, alors arrêtez de considérer de quelle autre façon vous pouvez l'écrire. Outre l'utilisation de gardes, d'autres options incluent l'extraction des sous-expressions dans des fonctions ou de la mettre case expressions à l'intérieur du corps de la fonction, afin de pousser une partie de la correspondance de modèle vers le bas sur eux, ainsi que de la principale définition.

10voto

sepp2k Points 157757

Pour moi, il ressemble à la Correspondance de Modèle et les Gardes sont fondamentalement les mêmes. À la fois évaluer une condition, et si vrai exécutera l'expression accroché à elle. Ai-je raison de ma compréhension?

Pas tout à fait. Premier filtrage ne peut pas évaluer arbitraire conditions. Il ne peut vérifier si une valeur a été créé à l'aide d'un constructeur donné.

Deuxième pattern matching peut lier les variables. Ainsi, alors que le modèle [] pourrait être l'équivalent de la garde - null lst (et non à l'aide de la longueur parce que j'avais pas équivalent - plus sur cela plus tard), le modèle x:xs plus n'est certainement pas équivalente à la garde - not (null lst) parce que le modèle lie les variables x et xs, qui la garde ne pas.

Une remarque sur l'utilisation de length: à l'Aide d' length afin de vérifier si une liste est vide, est une très mauvaise pratique, parce que, pour calculer la longueur qu'il doit parcourir toute la liste, qui prendra O(n) du temps, tout simplement vérifier si la liste est vide prend O(1) du temps avec null ou de pattern matching. Plus loin à l'aide de la longueur tout simplement ne fonctionne pas sur l'infinité des listes.

10voto

Justin Ethier Points 57486

Pour un, vous pouvez mettre des expressions booléennes à l'intérieur d'un garde.

Par exemple:

Tout comme avec les interprétations de la liste, des expressions booléennes peuvent être librement mélangés avec entre le modèle gardes. Par exemple:

f x | [y] <- x
    , y > 3
    , Just z <- h y
    = ...


Mise à jour

Il y a une belle citation d' Apprendre que Vous avez un Haskell à propos de la différence:

Alors que les modèles sont un moyen de s'assurer une valeur conforme à une certaine forme et le déconstruire, les gardes sont un moyen de tester si une propriété d'une valeur (ou plusieurs d'entre eux) sont vraies ou fausses. Cela sonne un peu comme une instruction if et c'est très semblable. Le truc, c'est que les gardes sont beaucoup plus lisible lorsque vous avez plusieurs conditions, et ils jouent vraiment bien avec des motifs.

5voto

I GIVE CRAP ANSWERS Points 12429

En plus de l'autre les bonnes réponses, je vais essayer d'être précis sur les gardes: Gardes sont tout sucre syntaxique. Si vous pensez cela, vous aurez souvent la structure suivante dans vos programmes:

f y = ...
f x =
  if p(x) then A else B

C'est, si le motif correspond, elle est suivie juste après par un si-alors-sinon la discrimination. Un garde les plis de cette discrimination dans la correspondance de modèle directement:

f y = ...
f x | p(x) = A
    | otherwise = B

(otherwise est True dans la bibliothèque standard). Il est plus commode qu'un si-alors-sinon de la chaîne et parfois rend le code beaucoup plus simple variante-sage, alors il est plus facile d'écrire que de la si-alors-sinon de la construction.

En d'autres termes, c'est du sucre sur le haut d'un autre de construction d'une manière qui simplifie grandement votre code dans de nombreux cas. Vous trouverez qu'il élimine beaucoup de si-alors-sinon chaînes et de rendre votre code plus lisible.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X