【问题标题】:How does the default definition of (<*>) in Haskell work?Haskell 中 (<*>) 的默认定义是如何工作的?
【发布时间】:2017-11-02 00:36:11
【问题描述】:

在 Haskell 中,(&lt;*&gt;) 运算符的默认实现(它将函数 a-&gt;b 的应用程序应用于 a 的应用程序,从而导致 b 的应用程序)在 Control.Applicative 中定义为 -

(<*>) :: f (a -> b) -> f a -> f b
(<*>) = liftA2 id

我根本无法理解它是如何工作的。

liftA2 的类型为liftA2 :: (a -&gt; b -&gt; c) -&gt; f a -&gt; f b -&gt; f c,这意味着它需要一个二进制函数,而id 不是。根据我的理解,这意味着 id 以某种方式被解释为某种更复杂的类型——但我不确定是哪个或如何使这个定义起作用。如果有人可以解释一下id 解释为什么类型(id :: a -&gt; a 定义中的a 代表什么类型),并了解它如何产生一个函数,该函数采用函数的应用程序和值的应用程序并应用它们,我将非常感激。

【问题讨论】:

  • -&gt; 是右结合。 a -&gt; b -&gt; c 表示a -&gt; (b -&gt; c)
  • 请注意,($)=id,仅用于不太通用的类型。该代码可以更清楚地写成ap = liftA2 ($)

标签: haskell functional-programming


【解决方案1】:

假设id 的类型是d -&gt; d,所以我们所有的类型变量都有不同的名称。现在让我们引入两个新的类型变量et 并说d = e -&gt; t。这使得id的类型:

id :: (e -> t) -> e -> t

现在这适合liftA2a = e -&gt; tb = ec = t 的第一个参数的类型。因此,通过这些分配,liftA2 的类型变为:

liftA2 :: ((e -> t) -> e -> t) -> f (e -> t) -> f e -> f t

如果我们应用第一个参数,剩下的类型变成f (e -&gt; t) -&gt; f e -&gt; f t,这正是&lt;*&gt;的类型(模重命名)。

【讨论】:

  • 应该是a = e -&gt; t而不是a = e -&gt; e
  • @kimsagro 是的,应该。固定的。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-21
  • 2012-04-23
  • 2016-12-06
  • 1970-01-01
相关资源
最近更新 更多