Je m'interrogee simplement sur une fonction de récursion que je pose à Haskell. Est-il généralement préférable d'utiliser des gardes que des motifs pour des fonctions de récursivité?
Je ne suis tout simplement pas sûr de la meilleure mise en page, mais je sais que les motifs sont meilleurs pour définir des fonctions telles que ceci: p> est beaucoup préféré à f y [] = []
f 0 (x:xs) =
f y (x:xs) =
5 Réponses :
une règle simple em> discussion em> p> fondamentalement, cela dépend du test que vous souhaitez faire pour protéger la récursivité. S'il s'agit d'un test sur la structure d'un type de données, utilisez la correspondance des motifs, car elle sera plus efficace que les tests redondants pour l'égalité. p> Pour votre exemple, la correspondance des schémas sur les entiers est évidemment propre et plus efficace: p> est identique à des appels récursifs sur n'importe quel type de données, où Vous distinguez les cas via la forme des données. P> Maintenant, si vous aviez des conditions logiques plus compliquées, les gardes auraient un sens. P> P>
Bon. Quel est le problème alors?
Tout simplement pas sûr de la terminologie: j'utilise quelque chose comme ceci: f y [] = [] code>
f y (x: xs) | x == 0 = ...... | Sinon = ...... code> serait-ce mieux en utilisant le motif correspondant à des gardes?
Sorte de pertinence, mais ne pose pas de pat motif sur les littéraux numériques descendants dans quelque chose comme des gardes de toute façon? Si je charge unités code> dans ghci avec
noimplicitpelude code> actif, GHC se plaint de
(==) code> ne pas être portée. Ou gère-t-il des motifs comme celui-là différemment parce que i> de
noimplicitpelude code>?
Si vous avez un ADT personnalisé et que vous souhaitez faire correspondre des constructeurs, la correspondance des motifs est la voie à suivre, elle s'applique également aux conditions simples (comme EQ). La correspondance des motifs ne fonctionnera pas sur des conditions plus complexes, c'est pourquoi vous avez des gardes, vous pouvez également utiliser la correspondance et les gardes combinés.
@CamCcan @Roman Gonzalez, donc essentiellement, je devrais utiliser le motif correspondant si cela fonctionne, non?
@camcann: Non, vous avez raison. Il descend de la correspondance des motifs. Le point clé est que l'utilisation de ce pragma, GHC prendra tout (==) code>, c'est dans la portée i>. Mais il n'y en a pas.
Ma règle générale serait ceci:
== code> chèque. li>
ul> avec récursion, vous vérifiez généralement un boîtier de base. Donc, si votre cas de base est un code == code>, puis utilisez la correspondance de modèle. P> donc je ferais généralement cela: p>
f _ [] = []
f 0 _ = ...
f y (x:xs) = ...
Vient de mettre à jour ma question pour en rendre un peu plus clair. La première partie a raison, je suis au courant de cela. Juste un peu moins certain sur la deuxième partie (i.e. carte f (x: xs) code> et si
f == 0 code>?
Il n'y a pas vraiment de règles difficiles et rapides à ce sujet, c'est pourquoi les réponses que vous avez obtenues étaient un peu floues. Certaines décisions sont faciles, comme la correspondance de modèle sur Par exemple, considérez ces fonctions (qui ne font pas vraiment quelque chose d'utile, servant simplement comme illustrations): P> [] code> au lieu de la protection avec
f xs | null xs = ... code> ou, heaven interdire,
f xs | Longueur XS == 0 = ... code> terrible de plusieurs manières. Mais quand il n'y a pas de problème pratique convaincant, il suffit d'utiliser le code plus clair.
f1 _ [] = []
f1 0 (x:xs) = [[x], xs]
f1 y (x:xs) = [x] : f1 (y - 1) xs
f2 _ [] = []
f2 y (x:xs) | y == 0 = calc 1 : f2 (- x) xs
| otherwise = calc (1 / y) : f2 (y * x) xs
where calc z = x * ...
+1 partagé où code> est une bonne raison de préférer les gardes sur la correspondance des motifs. Notez également qu'en raison de la paresse, si vous entrez un garde qui n'utilise pas une partie du
où code> expressions, ces expressions non utilisées ne seront jamais évaluées (car elles n'ont pas besoin d'être).
@Dan est correct: il s'agit essentiellement d'une question de préférences personnelles et n'affecte pas le code généré. Ce module: a produit le noyau suivant: p> exactement identique, à l'exception de la différence de cas par défaut, que dans les deux cas est une erreur de correspondance de modèle. GHC a même comméré les cordes pour les cas appariés. P> p>
Les réponses jusqu'à présent ne mentionnent pas l'avantage de la correspondance des motifs qui est la plus importante pour moi: la possibilité d'implémenter en toute sécurité les fonctions totales.
Lorsque vous faites correspondre la correspondance, vous pouvez accéder en toute sécurité à la structure interne de l'objet sans la peur. de cet objet étant autre chose. Si vous oubliez certains des motifs, le compilateur peut vous avertir (malheureusement cet avertissement est désactivé par défaut dans GHC). P>
Par exemple, lors de l'écriture: P>
-- compiles, crashes in runtime map f xs | not (null xs) = [] | otherwise = f (head xs) : map f (tail xs) -- does not have any way to compile map f (h:t) = [] map f [] = f h : map f t -- does not give any warnings map f xs = f (head xs) : map f (tail xs) -- can give a warning of non-exhaustive pattern match map f (h:t) = f h : map f t