Комбинатор liftM2 можно использовать в монаде Reader, чтобы сделать это «более функциональным» способом:
import Control.Monad
import Control.Monad.Reader
-- ....
filter (liftM2 (&&) odd (> 100)) [1..200]
Обратите внимание, что импорт важен; Control.Monad.Reader предоставляет экземпляр Monad (e ->), который заставляет все это работать.
Причина, по которой это работает, в том, что монада читателя просто (e ->) для некоторой среды e. Таким образом, логический предикат является 0-арной монадической функцией, возвращающей bool в среде, соответствующей его аргументу. Затем мы можем использовать liftM2 для распределения среды по двум таким предикатам.
Или, проще говоря, liftM2 будет работать примерно так, когда типы работают:
liftM2 f g h a = f (g a) (h a)
Вы также можете определить новый комбинатор, если хотите иметь возможность их легко связывать и / или не хотите связываться с 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]