12

该类Monad定义了一个>>方法,该方法对两个单子操作进行排序:

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

绑定运算符>>=具有等效的翻转参数,=<<; 一元函数组合('fish')运算符>=><=<. 不过,似乎没有<<(经过几分钟的 Hoogling)。为什么是这样?

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

4

2 回答 2

11

据我所知,没有充分的理由。请注意,您Monad也应该是 , 的实例Applicative,因此您可以使用<*and*>代替作为您的排序工具。

于 2013-01-05T21:48:41.833 回答
6

这是一个替代答案,因为最近提出了一个类似的问题并将其标记为重复。事实证明,根本不清楚(<<)应该是什么定义! 虽然在对旧答案的评论中提到了这个问题,但我认为这里没有完全清楚地表明存在重大问题。

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

(<<) :: 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

类比应用运算符(<*)and (*>),很明显 new(<<)运算符应该保留从左到右的副作用顺序,并且只具有切换使用哪个动作的返回值的效果,因此定义 #1 显然是正确的。这具有理想的属性,<<并且<*将是(行为良好的)monad 的同义词,就像>>*>是同义词一样,因此不足为奇。

当然,与=<<and类比>>=,很明显翻转大于号的方向应该具有翻转参数的效果,因此定义 #2 显然是正确的。这具有理想的特性,即一元操作的管道:

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

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

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

这也保留了 Kleisli 运算符的身份:

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

这当然看起来他们应该持有。

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

于 2019-04-10T20:20:42.223 回答