Using foldr to define map and filter

Sunday, Dec 27, 2020
Functional Haskell

The patterns of foldr and foldl occur in surprising places. I don't have a good eye to see those yet. It turns out that our good old map and filter are foldr patterns:

-- recursive definition of map and filter
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : map f xs

filter :: (a -> Bool) -> [a] -> [a]
filter p [] = []
filter p (x:xs) = if p x then x : filter p xs
       	 	       	 else filter p xs

So, map f applied to empty list is an empty list while the expression for non-empty list involves processing head in a certain way and recursively applying map to tail. This is foldr with \x xs -> f x : xs as our function:

map' :: (a -> b) -> [a] -> [b]
map' f = foldr (\x xs -> f x : xs) []

Similarly, filter for non-empty list processes the head and recursively apply filter to tail:

filter' :: (a -> Bool) -> [a] -> [a]
filter' p = foldr (\x xs -> if p x then x : xs else xs) []

Prelude> (map' (^2) . filter' odd) [1..10]