问题
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
回答1:
Definitions:
(.) :: (b -> c) -> (a -> b) -> a -> c
filter :: (m -> Bool) -> [m] -> [m]
length :: Foldable t => t n -> Int
What is u
?
length . filter :: u
≡ (.) length filter :: u
Then we must solve a, b, c, t, n
:
a -> b ~ (m -> Bool) -> [m] -> [m]
b -> c ~ Foldable t => t n -> Int
It follows:
a ~ m -> Bool
b ~ Foldable t => t n
b ~ [m] -> [m]
c ~ Int
Trivially:
a = m -> Bool
b = [m] -> [m]
c = Int
We have to solve t, n
from b ~ Foldable t => t n
, i.e. [m] -> [m] ~ Foldable t => t n
.
t = ((->) [m])
n = [m]
Therefore, t n = [m] -> [m]
which trivially unifies.
Summarising:
(.) :: Foldable ((->) [m]) =>
(([m] -> [m]) -> Int)
-> ((m -> Bool) -> [m] -> [m])
-> (m -> Bool) -> Int
filter :: (m -> Bool) -> [m] -> [m]
length :: Foldable ((->) [m]) => ([m] -> [m]) -> Int
(.) length filter :: Foldable ((->) [m]) => (m -> Bool) -> Int
An easier way to understand why length . filter
is not what you want is to look at the definition of (.)
.
(.) g f x = g(f x)
Therefore:
(.) length filter
≡ \x -> length (filter x)
We know that filter x
is not a list.
Pointless versions you may consider:
(length .) . filter
filter >=> return . length
(fmap.fmap) length filter
(id ~> id ~> length) filter -- [1]
filter $* id $$ id *$ length -- [2]
lurryA @N2 (length <$> (filter <$> _1 <*> _2)) -- [3]
- Control.Compose
- Data.Function.Meld
- Data.Function.Tacit
回答2:
The right composition would be:
(length .) . filter :: (a -> Bool) -> [a] -> Int
which is equivalent to:
\pred xs -> length $ filter pred xs
as in:
\> let count = (length .) . filter
\> :type count
count :: (a -> Bool) -> [a] -> Int
\> count odd [1..3]
2
\> count even [1..3]
1
回答3:
Using "three laws of operator sections", we have
((length .) . filter) x y =
(length .) (filter x) y =
(length . filter x) y =
length (filter x y)
and
((length .) . filter) =
(.) (length .) filter =
(.) ((.) length) filter =
((.) . (.)) length filter
The last bit, ((.).(.))
, is sometimes known as "owl operator", also written as .:
(length .: filter
), or fmap . fmap
(for functions, fmap
is (.)
).
来源:https://stackoverflow.com/questions/37972676/haskell-types-of-function-composition-not-matching