Quelle est la différence entre le filtrage et des Gardes?
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?
- Il n'est pas lié directement à votre question, mais la première version de la fonction est probablement meilleur parce qu'il est plus efficace et de travail pour l'infini des listes.
- Le filtrage est à propos de la forme de données, de gardes sur le contenu.
- Consultez le définition de la correspondance de motif dans le Langage Haskell Rapport.
Vous devez vous connecter pour publier un commentaire.
En fait, ils sont fondamentalement très différents! Au moins en Haskell, en tout cas.
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: Elles sont seule façon de déconstruire les données, et ils lier 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 unlet
expression) sont aussi une forme de motif, à la "normale" définitions des matches avec le trivial, un identifiant unique.Modèle 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 la manière, vous pouvez effectivement faire un filtrage au niveau supérieur déclarations:
C'est parfois utile pour un groupe de définitions connexes.
GHC aussi 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.
Que 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. Le
@
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 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 les détails que vous vous souciez.
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.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 gardenull lst
(pas à l'aide de la longueur parce que j'avais pas équivalent - plus sur cela plus tard), le modèlex:xs
est certainement pas équivalente à la gardenot (null lst)
parce que le modèle lie les variablesx
etxs
, dont la garde ne pas.Une remarque sur l'utilisation de
length
: à l'Aide delength
pour 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 prendraO(n)
temps, tout simplement vérifier si la liste est vide prendO(1)
temps avecnull
ou de pattern matching. Plus loin à l'aide de la longueur tout simplement ne fonctionne pas sur l'infinité des listes.Pour un, vous pouvez mettre des expressions booléennes à l'intérieur d'un garde.
Par exemple:
mise à Jour
Il y a une belle citation de Apprendre Vous un Haskell à propos de la différence:
Outre les autres 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:
Qui 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:
(
otherwise
est défini pour êtreTrue
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.
p x
plutôtp(x)
.