可以将((>> =)`重新声明为((a-> mb)-> ma-> mb`吗?

Tim*_*Tim -2 monads haskell

在Haskell Monad中声明为

class   Applicative m   =>  Monad   m   where
    return  ::  a   ->  m   a
    (>>=)   ::  m   a   ->  (a  ->  m   b)  ->  m   b
    return  =   pure
Run Code Online (Sandbox Code Playgroud)

我想知道是否可以将bind运算符重新声明为

(>>=)   ::  (a  ->  m   b)  ->  m   a   ->  m   b
Run Code Online (Sandbox Code Playgroud)

第二个声明使将(>>=)type a -> m b的函数映射到type 的函数m a -> m b更清晰,而原始的声明却使它的含义更不清楚,是否正确?

声明的更改是否会使某些事情变为可能,甚至是不可能,或者只需要对使用monad进行一些更改(Haskell程序员似乎可以接受)?

谢谢。

lef*_*out 15

为什么>>=在实践中比在翻转中更有用的原因是一个原因=<<:它与lambda表示法配合得很好。即,\充当语法先驱,因此您可以继续计算而无需任何括号。例如,

 do x <- [1..5]
    y <- [10..20]
    return $ x*y
Run Code Online (Sandbox Code Playgroud)

可以很容易地重写>>=

   [1..5] >>= \x -> [10..20] >>= \y -> return $ x*y
Run Code Online (Sandbox Code Playgroud)

您仍然具有与do版本相同的“命令式”感觉。

=<<此相反,它需要笨拙的括号,并且似乎向后看:

   (\x -> (\y -> return $ x*y) =<< [10..20]) =<< [1..5]
Run Code Online (Sandbox Code Playgroud)

好的,您可能会说这更像是函数应用程序。但是,如果有用,通常只使用应用函子接口而不是单子函数就更令人毛骨悚然了:

  (\x y -> x*y) <$> [1..5] <*> [10..20]
Run Code Online (Sandbox Code Playgroud)

或短

  (*) <$> [1..5] <*> [10..20]
Run Code Online (Sandbox Code Playgroud)

请注意,这(<*>) :: f (a->b) -> f a -> f b实际上=<<是您建议的顺序,只是a->在函子的内部而不是外部。

  • 它并没有使它更清晰。它使它成为“真”。原始声明*不会*将a-&gt; mb`类型的函数映射到`ma-&gt; mb`类型的函数;它将“ ma”类型的值映射到“(a-&gt; mb)-&gt; mb`”类型的函数。但是&gt;&gt;&gt;&gt;的目的并不是要映射事物,而是要“链接”计算。x &gt;&gt; = f的输出是适合另一个调用`&gt;&gt; =的左参数的值:`x &gt;&gt; = f &gt;&gt; = g &gt;&gt; = ...` (8认同)