Die liftM2 combinator kann im Reader Monade verwendet werden, dies zu tun in einer ‚funktionalen‘ Art und Weise:
import Control.Monad
import Control.Monad.Reader
-- ....
filter (liftM2 (&&) odd (> 100)) [1..200]
Hinweis, dass die Einfuhren sind wichtig; Control.Monad.Reader stellt die Monad (e ->) -Instanz zur Verfügung, mit der das alles funktioniert.
Der Grund, warum dies funktioniert, ist der Leser monad ist nur (e ->) für einige Umgebung e. Ein boolesches Prädikat ist also eine 0-wertige monadische Funktion, die bool in einer ihrem Argument entsprechenden Umgebung zurückgibt. Wir können dann liftM2 verwenden, um die Umgebung über zwei solche Prädikate zu verteilen.
Oder einfacher ausgedrückt, liftM2 wird ein bisschen so handeln, wenn die Arten funktionieren:
liftM2 f g h a = f (g a) (h a)
Sie können auch eine neue combinator definieren, wenn Sie diese einfach an die Kette in der Lage sein wollen, und/oder wollen nicht zu verwirren mit 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]
Beide Beispiele arbeiten auf GHC 7.6.3, auch wenn Sie 'Control.Monad.Reader' nicht importieren. – sjakobi
Ich kann 'liftM2' kann (heutzutage) wie folgt ersetzt werden:' filter ((&&) <$> ungerade <*> (> 100)) [1.200] '. Was gleich ist, aber schöner. :) Es erfordert auch nur "Control.Applicative" und keine vollständigen Monaden. ... Obwohl ich mich immer noch frage, welcher Operator AND mehr als zwei Boolesche Funktionen zulässt ... – Evi1M4chine