J'ai récemment rencontré des situations où je dois passer une fonction de prédicat à une autre fonction, et bien souvent la logique que je recherche est essentiellement "cette valeur correspond-elle à ce modèle?"
La correspondance de modèle semble être préférée dans les déclarations, les do
blocs et les listes de compréhension, mais il existe un certain nombre de fonctions qui prennent un prédicat a -> Bool
, où il serait très pratique de passer en quelque sorte un modèle. Par exemple, takeWhile
, until
, find
, span
, etc.
Jusqu'à présent, j'ai fait \a -> case a of MyCons _ -> True; otherwise -> False
ou écrit une fonction nommée à la fois, let myPred (MyCons _) = True; myPred _ = False in
mais elles semblent toutes les deux terriblement laides et pas très idiomatiques. La façon "évidente" (et erronée) serait quelque chose comme \(MyCons _) -> True
ça, mais cela jette une erreur pour être partiel, naturellement, et même alors, il semble qu'il doit y avoir une manière plus propre.
Existe-t-il une manière plus succincte / propre de faire ce genre de choses? Ou est-ce que je vais tout à fait mal?
let
clause que vous n'aimez pas - bien que je préfère lawhere
clause équivalente afin que cela n'encombre pas la définition principale. Bien sûr, si vous finissez par avoir besoin de cet utilitaire plus d'une fois, vous le définirez comme une fonction de niveau supérieur.let myPred...
style est mauvais , mais il semble beaucoup plus verbeux que ce à quoi je m'attendais pour une idée très simple, ce qui m'amène à me demander si j'aboie le mauvais arbre.maybe :: b -> (a -> b) -> Maybe a -> b
etbool :: a -> a -> Bool -> a
, puis à l'utiliser avec des fonctions de production booléennes comme argument (s). par exemplemyCons z f (MyCons x) = f x ; myCons z f _ = z
, puis appelezmyCons False (const True) aMyConsValue
. c'est presque ce que vous avez écrit, il y a juste un niveau supplémentaire "d'indirection" / "abstraction" via des arguments fonctionnels, incorporés dans celui-ci.Réponses:
Vous pouvez utiliser l'extension de langue LambdaCase à utiliser
\case MyCons _ -> True; _ -> False
, bien que cela n'enregistre pas autant de caractères.Je pense que vous pourriez écrire une série de fonctions
constructedWith :: (Generic a) => (b -> a) -> a -> Bool
,constructedWith2 :: (Generic a) => (b -> c -> a) -> a -> Bool
mais je ne suis pas assez compétent avec Generics pour l'implémenter sans quelques heures de test. Je vais essayer cela et modifier ma réponse si je peux le comprendre ou s'il s'agit d'une impasse.EDIT: Oui, vous pouvez le faire! Voici un lien vers mon code, qui implémente tout à partir de zéro:
https://repl.it/@lalaithion/ConstructedWith
Cependant, l'utilisation de quelque chose comme http://hackage.haskell.org/package/generic-deriving-1.13.1/docs/Generics-Deriving-ConNames.html pour toute la plomberie de code générique pourrait être meilleure.
la source