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

zer*_*ing 5 haskell zipwith

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

Prelude Control.Applicative> :t zipWith id
zipWith id :: [b -> c] -> [b] -> [c]
Run Code Online (Sandbox Code Playgroud)

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

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

当我id转到时,签名是如何申请的zipWith

Wil*_*sem 14

类型zipWith是:

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
Run Code Online (Sandbox Code Playgroud)

而类型id是:

id :: d -> d
Run Code Online (Sandbox Code Playgroud)

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

  d -> d
~ a -> (b -> c)
Run Code Online (Sandbox Code Playgroud)

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

   zipWith id :: [a] -> [b] -> [c]
-> zipWith id :: [b -> c] -> [b] -> [c]
Run Code Online (Sandbox Code Playgroud)

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

例如:

Prelude> zipWith id [(+1),(5/),(3*),(3-)] [1,4,2,5]
[2.0,1.25,6.0,-2.0]
Run Code Online (Sandbox Code Playgroud)

因为1+12.0,5/41.25,3*2现在6.03-5-2.0.

因此,zipWith id将采取两个元素fx,并应用id f x这些,或更详细(id f) x.由于id fIS f,它会由此计算f x.

因此,我们可以得出结论,这zipWith是一个元素映射.


pam*_*amu 5

谢谢你,Willem Van Onsem的答案很棒.

让我们zipWith id从ghc的类型推理系统的眼睛中理解.

首先,考虑一下 zipWith

Prelude> :info zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
    -- Defined in ‘GHC.List’
Run Code Online (Sandbox Code Playgroud)

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

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

现在考虑zipWith id.类型id是来自a -> a

我们已经放置id了一个两个参数函数必须去的地方.

因此,类型推断会(a -> b -> c)看起来像a -> (b -> c)(通知a -> (b -> c)需要一个arument a并给出b -> cie一个参数函数.)

但是,a -> (b -> c)只有在a(b - > c)时才能生成身份函数.

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

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

替换a为(b - > c).

使(a - > b - > c)看起来像id.(a - > b - > c)可以id通过上面的替换看起来像.

((B - > C) - >乙- > c)中也可以被写为((B - > C) - >(B - > C)),其是id :: x -> x其中x是(二- > c)中

zipWith :: ((b -> c) -> b -> c) -> [b -> c] -> [b] -> [c]
Run Code Online (Sandbox Code Playgroud)

所以最后我们得到输出 [b -> c] -> [b] -> [c]