运算符结合性、结合律和 monad 的值依赖性如何结合在一起?

bob*_*bob 4 monads haskell functional-programming associativity monoids

一方面,一元绑定运算符>>=是左结合的(AFAIK)。另一方面,monad 定律需要结合性,即评估顺序无关紧要(就像幺半群一样)。此外,monads 通过使下一个效果依赖于前一个效果的结果来编码值依赖,即 monads 有效地确定评估顺序。这对我来说听起来很矛盾,这显然意味着我对所涉及概念的心理表征是错误的。这一切是如何结合在一起的?

lef*_*out 8

一方面,一元绑定运算符>>=是左结合的

是的。

Prelude> :i >>=
class Applicative m => Monad (m :: * -> *) where
  (>>=) :: m a -> (a -> m b) -> m b
  ...
    -- Defined in ‘GHC.Base’
infixl 1 >>=
Run Code Online (Sandbox Code Playgroud)

这就是它的定义方式+也是左结合的,尽管(加法)群定律需要结合性。

Prelude> :i +
class Num a where
  (+) :: a -> a -> a
  ...
    -- Defined in ‘GHC.Num’
infixl 6 +
Run Code Online (Sandbox Code Playgroud)

所有的infixl声明意味着,编译器将解析 a+b+c(a+b)+c; 这是否恰好等于是a+(b+c)另一回事。

monad 法则需要结合性

嗯,>>=其实是联想的。关联运算符是>=>。对于>>=,类型已经表明它不能是关联的,因为第二个参数应该是一个函数,第一个不是。

此外,monad 通过使下一个效果依赖于前一个效果的结果来编码值依赖

是的,但这与 的结合性并不矛盾>=>。例子:

teeAndInc :: String -> Int -> IO Int
teeAndInc name val = do
   putStrLn $ name ++ "=" ++ show val
   return $ val + 1
Run Code Online (Sandbox Code Playgroud)
Prelude Control.Monad> ((teeAndInc "a" >=> teeAndInc "b") >=> teeAndInc "c") 37
a=37
b=38
c=39
40
Prelude Control.Monad> (teeAndInc "a" >=> (teeAndInc "b" >=> teeAndInc "c")) 37
a=37
b=38
c=39
40
Run Code Online (Sandbox Code Playgroud)

翻转括号不会改变动作之间的顺序/依赖关系(这将是交换律,而不是结合律),它只是改变了动作的分组

  • @scriptum:我认为你只是在这里混淆了“关联性”的两个概念:[运算符关联性](https://en.wikipedia.org/wiki/Operator_associativity)和[关联属性](https://en .wikipedia.org/wiki/Associative_property)。“`>>=` is *left-associative*” 只是意味着 `a >>= b >>= c` 被 *pars* 为 `(a >>= b) >>= c`,这只是为了方便,以避免编写一些括号。我们可以将其声明为“infix 1 >>=”。而“`>=>` 是*关联*”意味着“(a >=> b) >=> c”*等于*“a >=> (b >=> c)”,这是一个更强的声明关于实际的语义。 (5认同)