Haskell: Types of function composition not matching

廉价感情. 提交于 2019-12-11 01:24:08

问题


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]
  1. Control.Compose
  2. Data.Function.Meld
  3. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!