Functional Programming in C++, at page 214, with reference to an expected<T,E>
monad which is the same as Haskell's Either
, reads
[...] as soon as any of the functions you're binding to returns an error, the execution will stop and return that error to the caller.
Then, in a caption just below, it reads
If you call
mbind
[equivalent to Haskell's>>=
] on anexpected
that contains an error,,mbind
won't even invoke the transformation function; it will just forward that error to the result.
which seems to "adjust" what was written earlier. (I'm pretty sure that either LYAH or RWH underlines somewhere that there's no short-circuiting; if you remember where, please, remind me about it.)
Indeed, my understanding, from Haskell, is that in a chain of monadic bindings, all of the bindings happen for real; then what they do with the function passed to them as a second argument, is up to the specific monad.
In the case of Maybe
and Either
, when the bindings are passed a Nothing
or Left x
argument, then the second argument is ignored.
Still, in this specific two cases, I wonder if there's a performance penalty in doing something like this
justPlus1 = Just . (+1)
turnToNothing = const Nothing
Just 3 >>= turnToNothing >>= justPlus1
>>= justPlus1
>>= justPlus1
>>= justPlus1
>>= justPlus1
as in these cases the chain can't really do anything other than what it does, given that
Nothing >>= _ = Nothing
Left l >>= _ = Left l
Nothing
, but you do pay for unwinding the stack before that, but I'm not entirely sure. Continuation passing style is supposed to be more efficient in some way in some contexts, for example parser combinator libraries use CPS instead ofEither
for errors. – HjulleCont
/ContT
; if you have an existing monad and don’t want to rewrite it to use CPS internally to avoid costly left-associated binds, you can useCodensity
to do it automatically (shallowly). – Jon Purdy