【问题标题】:How does the second parameter become a list of functions?第二个参数如何变成函数列表?
【发布时间】:2017-08-04 14:27:47
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 值得注意的是,这更常写成zipWith ($)。其工作方式完全相同; $ 运算符只是 id 的类型缩小版本。
  • 如果你“试图分析”,你应该包括你试图分析的细节,否则潜在的回答者可能只是简单地重新解释你理解的东西,而完全忽略你不理解的东西't。

标签: haskell zipwith


【解决方案1】:

zipWith的类型是:

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

而id的类型是:

id :: d -> d

所以如果我们现在想推导出zipWith id 的类型,我们将id :: d -> d 的类型推入zipWith 的第一个参数的类型中:

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

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

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

这是如何工作的:第一个列表必须包含函数列表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]

因为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 f 是f,因此它会计算出f x。

因此我们可以得出结论,zipWith 是一个 elementwise 映射。

【讨论】:

  • ~ 是什么意思?
  • @zero_coding:意思是type equality。例如a ~ d 意味着a 和d 是相同的类型。 further reading.
  • @zero_coding 我添加了一个答案,可以让您在没有~ 的情况下理解。只是简单的类型推理逻辑。但是,@Willem Van Onsem 的回答真的很棒。
【解决方案2】:

感谢 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 id。 id 的类型来自 a -> a

我们已将id 放在一个必须包含两个参数的函数的位置。

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

但是,只有当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) -> b -> c) 也可以写成 ((b -> c) -> (b -> c)) 这是id :: x -> x 其中x 是 ( b -> c)

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-12
    • 2013-07-25
    • 1970-01-01
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多