I am having some troubles with function composition and types.
I would like to compose filter
(which returns a list) with len
, which takes a list as an argument (technically a Foldable
but I am simplifying here).
Looking at the types everything is as expected:
> :t length
length :: Foldable t => t a -> Int
> :t filter
filter :: (a -> Bool) -> [a] -> [a]
So now I would expect the type of (len . filter)
to be
(length . filter) :: (a -> Bool) -> [a] -> Int
while in reality is
> :t (length . filter)
(length . filter) :: Foldable ((->) [a]) => (a -> Bool) -> Int
So it seems I lost some arguments. Is it included in the the Foldable
requirements in some way I am not understanding?
Note that everything works as expected if I do partial application:
> let myFilter = filter odd
> :t myFilter
myFilter :: Integral a => [a] -> [a]
> :t (length . myFilter)
(length . myFilter) :: Integral a => [a] -> Int
> (length . myFilter) [1,2,3]
2
The right composition would be:
which is equivalent to:
as in:
Definitions:
What is
u
?Then we must solve
a, b, c, t, n
:It follows:
Trivially:
We have to solve
t, n
fromb ~ Foldable t => t n
, i.e.[m] -> [m] ~ Foldable t => t n
.Therefore,
t n = [m] -> [m]
which trivially unifies.Summarising:
An easier way to understand why
length . filter
is not what you want is to look at the definition of(.)
.Therefore:
We know that
filter x
is not a list.Pointless versions you may consider:
Using "three laws of operator sections", we have
and
The last bit,
((.).(.))
, is sometimes known as "owl operator", also written as.:
(length .: filter
), orfmap . fmap
(for functions,fmap
is(.)
).