的Monad类定义了一个>>方法,该方法序列的两个一元操作:
>> :: Monad m => m a -> m b -> m b
Run Code Online (Sandbox Code Playgroud)
绑定运算符>>=具有翻转参数等价物=<<; 和monadic函数组合('fish')运算符>=>和<=<.<<虽然(在Hoogling几分钟之后)似乎没有.为什么是这样?
编辑:我知道这不是什么大问题.我只是喜欢使用左指向运算符看某些代码行的方式.x <- doSomething =<< doSomethingElse只是看起来更好,箭头都是一样的,而不是x <- doSomethingElse >>= doSomething.
Phi*_* JF 11
据我所知,没有充分的理由.请注意,您Monad也应该是一个实例Applicative,因此您可以使用<*而*>不是作为您的测序工具.
这是一个替代答案,因为最近有人问过类似的问题并将其标记为重复。事实证明,到底(<<)应该定义什么还不清楚! 尽管在较旧答案的注释中提到了此问题,但我认为并没有完全清楚这里存在一个重大问题。
显然,定义的两个合理可能性是:
(<<) :: 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
Run Code Online (Sandbox Code Playgroud)
与应用运算符(<*)和相似(*>),很明显,新(<<)运算符应保留副作用从左到右的顺序,并且仅具有切换使用哪个动作的返回值的效果,因此定义#1显然是正确的。它具有理想的特性,<<并且<*将成为(行为良好的)单子的同义词,正如>>和*>的代名词一样,因此不会感到惊讶。
当然,通过与=<<和进行类比>>=,很明显,将大于号的方向翻转应该具有翻转自变量的效果,因此定义#2显然是正确的。这具有单子运算管道的理想特性:
u >>= v >>= w >> x >>= y
Run Code Online (Sandbox Code Playgroud)
可以通过翻转运算符来反转:
y =<< x << w =<< v =<< u
Run Code Online (Sandbox Code Playgroud)
这也保留了Kleisli运算符的身份:
(f >=> g) x === f x >>= g
(f <=< g) x === f =<< g x
Run Code Online (Sandbox Code Playgroud)
当然看起来他们应该坚持。
无论如何,我不知道这是否是最初的原因(<<)。(可能不会,因为该决定早于引入应用运算符,因此人们将“定义#2”作为唯一的可能性),但是我很确定这将是一个症结所在,因为不同的行为的(<<)和(<*)将给予密切的关联人合用的单子和操作之间的预期是相当意外的。