Le liftM2 combinateur peut être utilisé dans la monade Reader pour le faire d'une manière « plus fonctionnelle »:
import Control.Monad
import Control.Monad.Reader
-- ....
filter (liftM2 (&&) odd (> 100)) [1..200]
Notez que les importations sont importantes; Control.Monad.Reader fournit l'instance Monad (e ->) qui fait que tout cela fonctionne.
La raison pour laquelle cela fonctionne est la monade du lecteur est juste (e ->) pour un environnement e. Ainsi, un prédicat booléen est une fonction monophique 0-aire retournant booléen dans un environnement correspondant à son argument. Nous pouvons ensuite utiliser liftM2 pour répartir l'environnement sur deux de ces prédicats.
Ou, en termes plus simples, liftM2 agira un peu comme quand les types fonctionnent sur:
liftM2 f g h a = f (g a) (h a)
Vous pouvez également définir une nouvelle Combinator si vous voulez être en mesure de chaîner ces facilement, et/ou ne veulent pas se salir avec liftM2:
(.&&.) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)
(.&&.) f g a = (f a) && (g a)
-- or, in points-free style:
(.&&.) = liftM2 (&&)
filter (odd .&&. (> 5) .&&. (< 20)) [1..100]
Les deux exemples fonctionnent sur GHC 7.6.3 même si vous n'importez pas 'Control.Monad.Reader'. – sjakobi
Je suis 'liftM2' peut (de nos jours) peut être remplacé comme ceci:' filtre ((&&) <$> impaire <*> (> 100)) [1.200] '. Ce qui est pareil, mais plus joli. :) Il nécessite également seulement 'Control.Applicative', et pas de monades complètes. ... Bien que je me demande encore quel opérateur autorise ET plus de deux fonctions booléennes ... – Evi1M4chine