第二个参数如何成为函数列表?

时间:2017-08-04 14:27:47

标签: haskell zipwith

我正在玩zipWith并遇到以下情况:

Prelude Control.Applicative> :t zipWith id
zipWith id :: [b -> c] -> [b] -> [c]

为什么编译器期望下一个参数是一个函数列表?

我试图分析,但无法断定,为什么下一个参数必须是函数列表。

当我将id传递给zipWith时,签名是如何应用的?

2 个答案:

答案 0 :(得分:14)

zipWith的类型是:

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

id的类型是:

id :: d -> d

因此,如果我们现在想要派生zipWith id的类型,我们会将id :: d -> d的类型推送到zipWith的第一个参数的类型中:

  d -> d
~ a -> (b -> c)

这意味着:a ~ da ~ b -> c。这意味着zipWith id的类型现在是:

   zipWith id :: [a] -> [b] -> [c]
-> zipWith id :: [b -> c] -> [b] -> [c]

这是如何工作的:第一个列表必须包含函数列表f :: b -> c,第二个列表包含元素列表x :: b,因此它计算元素列表{{1 }}

例如:

f x :: c

由于Prelude> zipWith id [(+1),(5/),(3*),(3-)] [1,4,2,5] [2.0,1.25,6.0,-2.0] 1+12.05/41.253*26.03-5 }。

因此-2.0将采用两个元素zipWith idf,并对这些元素应用x,或者更详细id f x。由于(id f) xid f,因此会计算f

因此,我们可以得出结论f x元素映射。

答案 1 :(得分:5)

谢谢Willem Van Onsem的回答。

  

让我们从ghc的类型推理系统的角度理解zipWith id

首先,考虑zipWith

的类型
Prelude> :info zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
    -- Defined in ‘GHC.List’

zipWith的第一个参数是一个函数,它接受一个带有两个参数的函数。

(a -> b -> c)也可以重写为a -> (b -> c)

现在考虑zipWith idid的类型来自a -> a

我们已将id放在必须使用两个参数函数的位置。

因此,类型推断会使(a -> b -> c)看起来像a -> (b -> c)(注意a -> (b -> c)需要一个arument a并给出b -> c,即一个参数函数。)

但是,只有当a -> (b -> c)为(b - > c)时,才能使a成为身份函数。

a为(b - > c)时,函数a -> b -> c变为((b - > c) - >(b - > c))

因此,类型推理系统会将a推断为(b -> c),结果输出为[a] -> [b] -> [c],将a替换为b -> c

  

a替换为(b - > c)。

     

Make(a - > b - > c)看起来像id。通过上述替换,可以使(a - > b - > c)看起来像id

     

((b - > c) - > b - > c)也可写为((b - > c) - >(b - > c)),{{1其中id :: x -> x是(b - > c)

x

最后我们得到输出为zipWith :: ((b -> c) -> b -> c) -> [b -> c] -> [b] -> [c]