On the one hand the monadic bind operator >>=
is left associative (AFAIK). On the other hand the monad law demands associativity, i.e. evaluation order doesn't matter (like with monoids). Besides, monads encode a value dependency by making the next effect depend on the result of the previous one, i.e. monads effectively determine an evaluation order. This sounds contradictory to me, which clearly implies that my mental representation of the involved concepts is wrong. How does it all fit together?
On the one hand the monadic bind operator
>>=
is left associative
Yes.
Prelude> :i >>=
class Applicative m => Monad (m :: * -> *) where
(>>=) :: m a -> (a -> m b) -> m b
...
-- Defined in ‘GHC.Base’
infixl 1 >>=
That's just the way it's defined. +
is left-associative too, although the (addition-) group laws demand associativity.
Prelude> :i +
class Num a where
(+) :: a -> a -> a
...
-- Defined in ‘GHC.Num’
infixl 6 +
All an infixl
declaration means is that the compiler will parse a+b+c
as (a+b)+c
; whether or not that happens to be equal to a+(b+c)
is another matter.
the monad law demands associativity
Well, >>=
is actually not associative. The associative operator is >=>
. For >>=
, already the type shows that it can't be associative, because the second argument should be a function, the first not.
Besides, monads encode a value dependency by making the next effect depend on the result of the previous one
Yes, but this doesn't contradict associativity of >=>
. Example:
teeAndInc :: String -> Int -> IO Int
teeAndInc name val = do
putStrLn $ name ++ "=" ++ show val
return $ val + 1
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
Flipping around the parens does not change the order / dependency between the actions (that would be a commutativity law, not an associativity one), it just changes the grouping of the actions.
>>=
is left-associative” just means a >>= b >>= c
is parsed as (a >>= b) >>= c
, which is just for convenience, to avoid having to write some parentheses. We could declare it infix 1 >>=
instead. Whereas “>=>
is associative” means that (a >=> b) >=> c
is equal to a >=> (b >=> c)
, a much stronger statement about the actual semantics. –
Chemoprophylaxis © 2022 - 2024 — McMap. All rights reserved.
>>=
operator itself - if you check the standard statement of the law you will see it's somewhat more involved. It's equivalent in fact to the associativity (in the normal sense) of the Kleisli composition operator. – Anselado
notation to be multi-line (it doesn't have to be binary, like>>=
), to be re-grouped at will as long as the lines' order stays the same (so the inner brackets can be omitted). Just like the function composition's associativity means we can write composition chains non-parenthesized too. – Featheringop1 <> op2
operations are evaluated doesn't matter. I don't mean the order of operands but theoperand1 operator operand2
operations as a whole. However, this doesn't work for>>=
anyway, because of the underlying type. – Pietje>=>
. and its combinations too could be calculated in parallel, out of order! but, what it calculates is the combined action that is yet to be run. see? when the combined action runs, it'll run its constituent actions left-to-right, strictly in order. because that's how the underlying>>=
is defined. (you really should've included that example of your understanding in the question from the start!) – Feathering