Filtering a list of elements by a list of filters

Viewed 116

I was thinking how I could make it so that if I have a list of elements [1, 2, ... n], and a list of filters such as [(>3), (<4), ...], it would return the list of elements that have passed every filter.

Been trying this for a while and what I got so far is:

filt :: (a -> Bool) -> [a] -> [a]
filt f xs = filter f xs

This function is supposed to get a filter and a list of elements and return the list of elements that have passed one single filter.

And then,

filters :: [a] -> ([a] -> Bool) -> [a]
filters xs ps = (\p -> filt p xs) ps

which not only gives me error, but I also don't know if I'm doing it correctly. (I'm trying to have each filter of the filter list be an argument for the filt function, along with the list of elements.

New to Haskell, so any tips and tricks you guys wanna give me are highly appreciated!

2 Answers

and a list of filters such as [(>3), (<4), ...]

The signature is incorrect. This is a list of function a -> Bool, so you should use:

filters :: [a] -> [a -> Bool] -> [a]

This will however not be sufficient. You need to turn this into a filter that checks if all the predicates are satisfied. We can do by using all :: Foldable f => (b -> Bool) -> f b -> Bool. Here the b for the all function is a function a -> Bool, and thus the type of the function (b -> Bool) is (a -> Bool) -> Bool. We do this by calling each function on that element:

filters :: [a] -> [a -> Bool] -> [a]
filters xs fs = filter (\x -> all ($ x) fs) xs

we can further generalize the signature to:

filters :: Foldable f => [a] -> f (a -> Bool) -> [a]
filters xs fs = filter (\x -> all ($ x) fs) xs

Chaining the filters one after another,

filters :: [a] -> [a -> Bool] -> [a]
filters xs ps  =  foldr (\p r -> filter p r) xs ps

or, shorter,

filters :: [a] -> [a -> Bool] -> [a]
filters  =  foldr filter

Or we can use foldl' (flip filter), which pushes the list through filters in the left-to-right order.

Related