I don't understand why map . filter
generic type is map . filter :: (a -> Bool) -> [[a]] -> [[a]]
.
I know that map and filter types are map :: (a -> b) -> [a] -> [b]
and filter :: (a -> Bool) -> [a] -> [a]
. And also (.) :: (b -> c) -> (a -> b) -> a -> c
.
So my guess was that a = (a -> Bool) -> [a]
, b = [a]
and since the output of filter is not a function, I thought that map . filter
would return a function that expect a function (a -> b)
.
I don't understand why the type is a list of lists of a
, since neither map
nor filter
has a list of lists. I also don't understand why it works with just one function since both need one.
Can someone explain how does it work, please?
First, lets use different letters for the types in the functions. That way we won't get confused.
map :: (a -> b) -> [a] -> [b]
filter :: (c -> Bool) -> [c] -> [c]
(.) :: (e -> f) -> (d -> e) -> d -> f
So now we consider map . filter
. Doing the substitution we get the following (~
is used for type equality):
d ~ (c -> Bool)
e ~ ([c] -> [c]) -- Result of 'filter'
e ~ (a -> b) -- Argument of 'map'
f ~ ([a] -> [b])
Notice how we get two types for e
. By substitution,
a ~ b ~ [c]
So therefore
f ~ ([[c]] -> [[c])
And so we can substitute for d
and f
in the definition of (.)
and get
(c -> Bool) -> [[c]] -> [[c]]
Which is what GHCi was telling us.
What this function actually does is apply the filter to each sublist; the function argument taken by map
is the filter. So in GHCi,
Prelude> import Data.Char
Prelude Data.Char> (map.filter) isDigit ["foo123", "456bar"]
["123","456"]