开发者

haskell, chaining filters

开发者 https://www.devze.com 2022-12-10 21:50 出处:网络
to write \"map f (map g xs)\" as a single call to map you could write example xs = map (f.g) xs but how would you write \"filter p (filter q xs)\" as a single call to filt开发者_StackOverflower? t

to write "map f (map g xs)" as a single call to map you could write

example xs = map (f.g) xs

but how would you write "filter p (filter q xs)" as a single call to filt开发者_StackOverflower? the dot operator doesnt seem to work for filter as it does for maps. guessing you'd use something else for predicates?


If you defined a function both that looked like this:

both :: (a -> Bool) -> (a -> Bool) -> a -> Bool
both f g x = f x && g x

Then you could write:

example xs = filter (both p q) xs

I'm not sure if there's a standard function that does this for you...


$ ghci
Prelude> :m +Control.Arrow
Prelude Control.Arrow> :t uncurry (&&) . ((0 <) &&& (< 10))
uncurry (&&) . ((0 <) &&& (< 10)) :: (Num a, Ord a) => a -> Bool
Prelude Control.Arrow> filter (uncurry (&&) . ((0 <) &&& (< 10))) [0..15]
[1,2,3,4,5,6,7,8,9]

Or declare your own operators, if you'll be doing this often.

infixr 3 &&:
p &&: q = \a -> p a && q a
infixr 2 ||:
p ||: q = \a -> p a || q a
not' = (.) not
all' = foldr (&&:) $ const True
any' = foldr (||:) $ const False

example xs = filter (p &&: q ||: not' r) xs


Why not a list comprehension?

example = [x | x <- xs, p x, q x]
-- for example
example = [x | x <- [1..10], (>3) x, x<5 ] -- [4]


Calling a list of functions on something is essentially what the ap function in Control.Monad does. Then you just and the results. The only slight ugliness is that ap requires both its arguments to be in the same monad (List in this case), so we need to compose it with return to work here.

import Control.Monad
filterByMany funcs = filter (and . ap funcs . return)


I would define a lambda expression.

module Main where

overTen :: Int -> Bool
overTen = (>10)

main :: IO ()
main = do
    print $ filter (\x -> overTen x && even x) [1..20]

output:

$ ghci Test.hs
GHCi, version 6.10.4: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer ... linking ... done.
Loading package base ... linking ... done.
[1 of 1] Compiling Main             ( Test.hs, interpreted )
Ok, modules loaded: Main.
*Main> main
[12,14,16,18,20]
*Main>


import Data.Foldable
import Data.Monoid

p = (>4)
g = (<10)

main = print $ filter (getAll . foldMap (All.) [p,g]) [1..10]

outputs

[5,6,7,8,9]

just because lists are foldable, and you can combine predicate results with the All monoid


What about something like:

example xs = filter (forAll [p,q,r,s,t,u,v]) xs

forAll:: [(a -> Bool)] -> a -> Bool
forAll funcs x = all (map ($ x) funcs)


I'd define a helper function -- this could probably be written more declaratively, but I don't have GHCI installed on this system for testing:

allPredicates :: [a -> Bool] -> a -> Bool
allPredicates []     _ = True
allPredicates (p:ps) x = p x && allPredicates ps x

then

filter (allPredicates [p, q]) xs
0

精彩评论

暂无评论...
验证码 换一张
取 消