【问题标题】:Haskell: Types of function composition not matchingHaskell:函数组合的类型不匹配
【发布时间】:2016-10-24 16:04:15
【问题描述】:

我在函数组合和类型方面遇到了一些问题。 我想用len 组合filter(返回一个列表),它将一个列表作为参数(技术上是Foldable,但我在这里简化了)。 查看类型一切都符合预期:

> :t length
length :: Foldable t => t a -> Int

> :t filter
filter :: (a -> Bool) -> [a] -> [a]

所以现在我希望(len . filter) 的类型是

(length . filter) :: (a -> Bool) -> [a] -> Int

实际上是

> :t (length . filter)
(length . filter) :: Foldable ((->) [a]) => (a -> Bool) -> Int

看来我失去了一些论据。它是否以某种我不理解的方式包含在Foldable 要求中?

请注意,如果我进行部分应用,一切都会按预期进行:

> 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

【问题讨论】:

  • 要获得您期望的合成类型,您正在合成的每个函数都应采用“一个”参数。我把一个放在引号中,因为所有函数都接受一个参数。查看更多here
  • 请注意 (length . filter) x y 是 length (filter x) y 而不是 length (filter x y)。此外,filter 实际上是一个函数,它采用 one 参数a->Bool 并返回一个函数[a]->[a](回忆一下柯里化),该组合试图将其传递给length。
  • 如果像Num [a] 或任何带有(->) 的东西出现在约束中(即在=> 的左侧),这通常表明您基本上已经创建了类型错误,但 GHC 太客气了,不能这样称呼它,因为有人可以原则上定义一些荒谬的类实例,使其合法。

标签: haskell types functional-programming function-composition combinators


【解决方案1】:

正确的组合应该是:

(length .) . filter :: (a -> Bool) -> [a] -> Int

相当于:

\pred xs -> length $ filter pred xs

如:

\> let count = (length .) . filter
\> :type count
count :: (a -> Bool) -> [a] -> Int
\> count odd [1..3]
2
\> count even [1..3]
1

【讨论】:

  • 仔细检查我是否正确地关注:(length . ) . filter p = length . (filter p) 和 length . (filter p) xs = length ( (filter p) xs)。对不起所有额外的(),但这对我理解很有帮助。
  • @meto ((f .) . g) x 是 f . (g x) 和 (f . (g x)) y 是 f (g x y)
【解决方案2】:

定义:

(.) :: (b -> c) -> (a -> b) -> a -> c
filter ::  (m -> Bool) -> [m] -> [m]
length :: Foldable t => t n -> Int

u 是什么?

length . filter :: u
≡ (.) length filter :: u

那我们就要解决a, b, c, t, n:

a -> b ~ (m -> Bool) -> [m] -> [m]
b -> c ~ Foldable t => t n -> Int

如下:

a ~ m -> Bool
b ~ Foldable t => t n
b ~ [m] -> [m]
c ~ Int

琐碎:

a = m -> Bool
b = [m] -> [m]
c = Int

我们必须从b ~ Foldable t => t n解决t, n,即[m] -> [m] ~ Foldable t => t n。

t = ((->) [m])
n = [m]

因此,t n = [m] -> [m] 简单统一。

总结:

(.) :: 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

了解为什么length . filter 不是您想要的更简单的方法是查看(.) 的定义。

(.) g f x = g(f x)

因此:

(.) length filter
≡ \x -> length (filter x)

我们知道filter x 不是一个列表。


您可以考虑的无意义版本:

(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

【讨论】:

  • @WillNess 感谢您指出这个错误。我做了一个更正。它应该是filter &gt;=&gt; return . length。
【解决方案3】:

使用"three laws of operator sections",我们有

((length .) . filter) x y =
 (length .) (filter x) y =
 (length . filter x) y =
 length (filter x y)

和

((length .) . filter) = 
  (.) (length .) filter =
  (.) ((.) length) filter =
  ((.) . (.)) length filter

最后一位((.).(.)),有时称为"owl operator",也写为.:(length .: filter)或fmap . fmap(对于函数,fmap 是(.))。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-04
    • 2014-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多