How do you combine filter conditions

后端 未结 4 1486
悲哀的现实
悲哀的现实 2021-02-02 09:42

The filter class of functions takes a condition (a -> Bool) and applies it when filtering.

What is the best way to use a filter on when you have multiple conditions?

4条回答
  •  深忆病人
    2021-02-02 10:22

    The liftM2 combinator can be used in the Reader monad to do this in a 'more functional' way:

    import Control.Monad
    import Control.Monad.Reader
    
    -- ....
    
    filter (liftM2 (&&) odd (> 100)) [1..200]
    

    Note that the imports are important; Control.Monad.Reader provides the Monad (e ->) instance that makes this all work.

    The reason this works is the reader monad is just (e ->) for some environment e. Thus, a boolean predicate is a 0-ary monadic function returning bool in an environment corresponding to its argument. We can then use liftM2 to distribute the environment over two such predicates.

    Or, in simpler terms, liftM2 will act a bit like this when the types work out:

    liftM2 f g h a = f (g a) (h a)
    

    You can also define a new combinator if you want to be able to chain these easily, and/or don't want to mess with 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]
    

提交回复
热议问题