【问题标题】:Why is there no << in the Haskell standard library?为什么 Haskell 标准库中没有 <<?
【发布时间】:2013-01-05 21:38:22
【问题描述】:

Monad 类定义了一个&gt;&gt; 方法,该方法对两个单子动作进行排序:

>> :: Monad m => m a -> m b -> m b

绑定运算符&gt;&gt;= 有一个等效的翻转参数=&lt;&lt;;与一元函数组合('fish')运算符&gt;=&gt; 和&lt;=&lt; 一样。不过,似乎没有&lt;&lt;(经过几分钟的胡扯)。这是为什么呢?

编辑:我知道这没什么大不了的。我只是喜欢某些代码行与左指向运算符的外观。 x &lt;- doSomething =&lt;&lt; doSomethingElse 比x &lt;- doSomethingElse &gt;&gt;= doSomething 看起来更好,箭头方向都一样。

【问题讨论】:

  • 没有人为此辩护。
  • 他们做=&lt;&lt;和&lt;=&lt;的时候没想到吗?我不知道为什么它会困扰我,这似乎只是一个疏忽。
  • @MathematicalOrchid 是的,他们有。可怜的,显然他们没有想到,或者认为它没有说服力。
  • @MathematicalOrchid 它们都将x 绑定到monad doSomething &gt;&gt;= doSomethingElse 内的对象,这与doSomethingElse =&lt;&lt; doSomething 相同。 RHS 在分配之前会被完全评估,就像在命令式语言中一样。
  • @poorsod 好吧,&lt;=&lt; 和 =&lt;&lt; 出现而 &lt;&lt; 没有出现是有原因的(无论是过去的决策,还是决策) .您的示例说明,x &lt;- amb =&lt;&lt; ma 或多或少是自然的,x &lt;- mb &lt;&lt; ma 不是,您可以在上面的行中写上ma,而只需写上x &lt;- mb。

标签: haskell monads


【解决方案1】:

据我所知,没有充分的理由。请注意,您的Monad 也应该是Applicative 的一个实例,因此您可以使用&lt;* 和*&gt; 作为您的测序工具。

【讨论】:

  • 但请注意,虽然*&gt; 等价于&gt;&gt;,但a &lt;* b 不等价于b *&gt; a。
  • @dave4420 这是一个很好的观点。 flip (*&gt;) 和 flip (&gt;&gt;) 始终是一个选项。
【解决方案2】:

这是一个替代答案,因为最近提出了一个类似的问题并标记为重复。事实证明,完全不清楚 (&lt;&lt;) 的定义应该是什么!虽然这个问题在旧答案的 cmets 中有所提及,但我认为它并没有完全清楚这里有一个严重的问题。

显然,定义的两种合理可能性是:

(<<) :: Monad m => m a -> m b -> m a
p << q = do {x <- p; q; return x}   -- definition #1
p << q = do {q; p}                  -- definition #2

类比应用运算符(&lt;*) 和(*&gt;),很明显新的(&lt;&lt;) 运算符应该保留从左到右的副作用顺序,并且只具有切换使用哪个动作的返回值的效果,所以定义#1 显然是正确的。这具有理想的属性,&lt;&lt; 和 &lt;* 将是(行为良好的)monad 的同义词,就像 &gt;&gt; 和 *&gt; 是同义词一样,所以没有什么意外。

当然,通过类比=&lt;&lt; 和&gt;&gt;=,很明显翻转大于号的方向应该具有翻转参数的效果,所以定义#2 显然是正确的。这具有一元操作管道的理想属性:

u >>= v >>= w >> x >>= y

可以通过翻转运算符来反转:

y =<< x << w =<< v =<< u

这也保留了 Kleisli 操作员的身份:

(f >=> g) x  ===  f x >>= g
(f <=< g) x  ===  f =<< g x

这确实看起来他们应该持有。

无论如何,我不知道这是否是(&lt;&lt;) 被忽略的最初原因。 (可能不会,因为该决定会早于应用运算符的引入,所以人们会认为“定义#2”是唯一的可能性),但我很确定现在这将是一个症结所在,因为不同的行为考虑到人们期望 applicative 和 monad 操作之间的密切关联,(&lt;&lt;) 和 (&lt;*) 的组合非常出乎意料。

【讨论】:

  • (&lt;*) 和 (*&gt;) 不是彼此保持效果顺序的变体;它们是(&lt;*&gt;) 的变体,对所包含值的组合较少。因此,第一段中的正确类比是,就像 (&gt;&gt;) 是 (&gt;&gt;=) 的变体,它对包含的值进行较少的组合,(&lt;&lt;) 应该是 (=&lt;&lt;) 的变体,它对包含的值的组合较少包含的值。 (没有超级组合 &gt;&gt;=&lt;&lt; 或任何 (&gt;&gt;) 和 (&lt;&lt;) 应该是变体。)这使两个论点和谐一致,坚定地支持定义#1的一面。
  • @K.A.布尔感谢您回答这个问题。我非常不同意@DanielWagner,#1 的定义真的会令人困惑和无用,因为&lt;* 真的可以用来代替它。另一方面,定义#2 实际上可以用于编写清晰的代码,即与&lt;=&lt; 和=&lt;&lt; 组合在一起。
  • @lehins 是的,我检查了又仔细检查了一遍,但还是弄错了:我的评论应该说“......坚定地支持定义 #2 的一面。”。
猜你喜欢
  • 1970-01-01
  • 2014-06-28
  • 2021-11-10
  • 2016-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-13
相关资源
最近更新 更多