我正在玩一下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 ~ d和a ~ 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+1是2.0,5/4是1.25,3*2现在6.0和3-5是-2.0.
因此,zipWith id将采取两个元素f和x,并应用id f x这些,或更详细(id f) x.由于id fIS f,它会由此计算f x.
因此,我们可以得出结论,这zipWith是一个元素映射.
谢谢你,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]替换a为b -> 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]