【问题标题】:What does Haskell's <|> operator do?Haskell 的 <|> 运算符是做什么的?
【发布时间】:2014-11-18 02:12:04
【问题描述】:

浏览 Haskell 的文档对我来说总是有点痛苦,因为您获得的有关函数的所有信息通常只是:f a -&gt; f [a],这可能意味着任何数量的东西。

&lt;|&gt; 函数一样。

我得到的只是:(&lt;|&gt;) :: f a -&gt; f a -&gt; f a,这是一个 “关联二元运算”...

在检查 Control.Applicative 后,我了解到它会根据实施情况做一些看似无关的事情。

instance Alternative Maybe where
    empty = Nothing
    Nothing <|> r = r
    l       <|> _ = l

好的,所以如果没有左则返回右,否则返回左,明白了。这让我相信这是一个“左或右”运算符,考虑到它使用| 和@,这有点道理987654328@ 历史上用作“或”

instance Alternative [] where
    empty = []
    (<|>) = (++)

除了这里它只是调用列表的连接运算符...打破我的想法...

那么这个函数到底是什么?它有什么用?它在宏伟的计划中处于什么位置?

【问题讨论】:

  • 对于诸如&lt;|&gt; 之类的极其通用的操作只需要很少的内容。 “理解”它们的正确方法是理解具体实例。即,如果您想在Maybe 上使用&lt;|&gt;,那么请了解它对Maybe 的作用...
  • 嗯,这是Monoid&lt;&gt; 操作,它在a 中是多态的。
  • 列表实例是因为将列表解释为元素的非确定性选择。如果您阅读 &lt;|&gt; 的意思是“orelse”,那么对于两个非确定性列表,您会从其中一个获得非确定性的可能性,因此 (++)
  • 啊,但这就是您需要了解的全部内容。与一个单元的关联二元运算是一个幺半群。 List monoid 以空列表为单位,(++) 为关联二元运算。
  • @SassaNF 但是您可以为列表创建至少两个完全不同的应用程序和替代实例,例如 ZipList。见this question

标签: haskell applicative alternative-functor


【解决方案1】:

(&lt;|&gt;) :: f a -&gt; f a -&gt; f a 实际上告诉你很多,即使不考虑Alternative 的法律。

它需要两个f a 值,并且必须返回一个。所以它必须以某种方式组合或从它的输入中选择。它在a 类型中是多态的,因此它将完全无法检查a 类型的任何值可能在f a 中;这意味着它不能通过组合 a 值来进行“组合”,因此它必须纯粹根据类型构造函数 f 添加的任何结构来进行。

这个名字也有点帮助。某种“OR”确实是作者试图用名称“Alternative”和符号“”来表示的模糊概念。

现在,如果我有两个 Maybe a 值并且我必须将它们组合起来,我该怎么办?如果他们都是Nothing,我将返回Nothing,但无法创建a。如果其中至少一个是Just ...,我可以按原样返回我的输入之一,或者我可以返回NothingMaybe a -&gt; Maybe a -&gt; Maybe a 类型的函数很少可能,对于名称为“Alternative”的类,给出的函数非常合理和明显。

组合两个[a] 值怎么样?这里有更多可能的功能,但实际上很明显这可能会做什么。并且“替代”这个名称确实可以很好地提示您这可能是什么提供您熟悉列表单子/应用程序的标准“非确定性”解释;如果您将[a] 视为具有可能值集合的“非确定性a”,那么以一种可能值得称为“替代”的方式“组合两个非确定性a 值”的明显方法是产生一个不确定的a,它可以是来自任一输入的任何值。

对于解析器;结合两个解析器有两个明显的广泛解释,让人想到;要么你生成一个解析器,它会匹配第一个所做的,然后是第二个所做的,或者你生成一个解析器,它匹配 either 第一个所做的 第二个所做的(当然,这些选项中的每一个都有微妙的细节,为选项留出了空间)。鉴于名称“替代”,“或”解释对于 &lt;|&gt; 来说似乎很自然。

所以,从足够高的抽象层次来看,这些操作都“做同样的事情”。类型类实际上是为了在这些东西“看起来都一样”的高抽象级别上运行。当我对单个已知实例进行操作时,我只是认为&lt;|&gt; 操作正是它对特定类型所做的操作。

【讨论】:

  • 成分只是类型类的名称、操作符的类型签名和一些具体实例的具体例子。结果是理解Alternative 类型类的秘诀。我想知道这种方法是否足以解释其他广义的 FP 概念。谢谢!
【解决方案2】:

这些看起来非常不同,但请考虑:

Nothing <|> Nothing == Nothing
     [] <|>      [] ==      []

Just a  <|> Nothing == Just a
    [a] <|>      [] ==     [a]

Nothing <|> Just b  == Just b
     [] <|>     [b] ==     [b]

所以...这些实际上非常非常相似,即使实现看起来不同。唯一真正的区别在这里:

Just a  <|> Just b  == Just a
    [a] <|>     [b] ==     [a, b]

Maybe 只能保存 一个 值(或零,但不能保存任何其他数量)。但是,嘿,如果它们都相同,你为什么需要两种不同的类型?它们不同的全部意义在于,你知道,不同

总之,实现可能看起来完全不同,但实际上非常相似。

【讨论】:

    【解决方案3】:

    Alternative 不是解析器或类似 MonadPlus 的东西的一个有趣示例是 Concurrentlyasync 包中的一个非常有用的类型。

    对于Concurrentlyempty 是一个永远持续的计算。 (&lt;|&gt;) 同时执行它的参数,返回第一个完成的结果,并取消另一个。

    【讨论】:

      【解决方案4】:

      通常它表示“选择”或“并行”,因为a &lt;|&gt; babab 并行完成的“选择”。但是,让我们备份。

      真的,像(&lt;*&gt;)(&lt;|&gt;) 这样的类型类中的操作没有实际意义。这些操作以两种方式赋予意义:(1)通过法律和(2)通过实例化。如果我们不是在讨论Alternative特定 实例,那么只有 (1) 可用于直觉意义。

      所以“关联”意味着a &lt;|&gt; (b &lt;|&gt; c)(a &lt;|&gt; b) &lt;|&gt; c 相同。这很有用,因为这意味着我们只关心与(&lt;|&gt;) 链接在一起的事物的序列,而不是它们的“树结构”。

      其他法律包括empty 的身份。特别是a &lt;|&gt; empty = empty &lt;|&gt; a = a。在我们对“选择”或“并行”的直觉中,这些定律读作“一个或(不可能的事情)必须是一个”或“一个并列(空过程)只是一个”。它表明emptyAlternative 的某种“故障模式”。

      (&lt;|&gt;)/emptyfmap(来自Functor)或pure/(&lt;*&gt;)(来自Applicative)如何交互还有其他规律,但也许是前进的最佳方式理解(&lt;|&gt;) 的含义是检查一个实例化Alternative 的类型的一个非常常见的示例:a Parser

      如果x :: Parser Ay :: Parser B(,) &lt;$&gt; x &lt;*&gt; y :: Parser (A, B) 依次解析x 然后 y。相反,(fmap Left x) &lt;|&gt; (fmap Right y) 解析 either xy,以 x 开头,以尝试两种可能的解析。换句话说,它表示解析树中的一个分支、一个选择或一个并行解析域。

      【讨论】:

      • 但在&lt;*&gt; 的情况下,它或多或少总是相同的。 (Just (+3)) &lt;*&gt; (Just 4) 给出Just 7[(+3)] &lt;*&gt; [1..3] 给出[4,5,6],就像你对map 操作所期望的一样。它的含义并没有真正因实例而异
      • @ElectricCoffee 这并非完全正确。例如,首先考虑类型ZipList a 本质上与[a] 相同。现在[(+1),(+2)] &lt;*&gt; [1,2] = [2,3,3,4]ZipList [(+1),(+2)] &lt;*&gt; ZipList [1,2] = ZipList [2,4]。因此,(&lt;*&gt;) 的含义并不总是那么清楚。
      • 我只是想建议(&lt;*&gt;) 的含义有共同的主题,是的——这些主题是通过仔细检查其规律而暴露出来的——但我很难接受它实例到实例基本相同。
      • 有人用foldl1(&lt;|&gt;)展示了一个很好的例子,这实际上展示了它的一些力量
      • (&lt;|&gt;) 的关联性意味着折叠很有用。折叠“修复”线性树结构(完全左嵌套或完全右嵌套),并且只有由于关联性,我们才知道我们可以忽略这种可能的重新排列的含义。
      猜你喜欢
      • 2014-09-16
      • 2013-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多