4 ms·
That is a misconceptio and is only possible if you break monad laws. Monads aren't about sequencing. Just some monads are. (+) <$> a <*> b And x <-
by arianvanp 12y ago
That is a misconceptio and is only possible if you break monad laws. Monads aren't about sequencing. Just some monads are.
(+) <$> a <*> b
And
x <- a
y <- b
return (a + b)
Will yield exactly the same behaviour. Even in evaluation order. And they can be interchanged. It may look like we are sequencing in the second example but that's only true in datatype with sequencing embodied in their monad and application implementation ( State monad). An example of a datatype that doesn't have this property is [a]
- wyager 12y agoEven the state monad is not actually sequential. It just appears that way conceptually. It can, just like most haskell code, end up being computed in any order (because of laziness and lambda calculus reordering rules). For the most part, only "special" monads like IO enforce sequential computation.
- judk 12y agoState is sequential when it matters x <- get put y z <- get
- tel 12y agoA good example demonstrating this is the "reverse state monad" http://lukepalmer.wordpress.com/2008/08/10/mindfuck-the-reverse-state-monad/ http://lukepalmer.wordpress.com/2008/08/10/mindfuck-the-reve... It sends state updates "back in time" to compute fixed points. The above article shows how you can compute the fibonacci stream using it.
- dragonwriter 12y ago> For the most part, only "special" monads like IO enforce sequential computation. No, IO doesn't either, because of laziness. If you need a demonstration, then, in the IO monad, open a file (using the functions in System.IO), read the contents (without doing anything else that depends on them), close the file, and then use the file contents. IO still works in data dependency order.
- wyager 12y agoYou are partially correct. All IO operations "start" in sequential order. Only some of them "finish" sequentially (like putStrLn).
- tel 12y agoThat behavior can be seen as a perversion of IO's behavior—it's roughly known as Lazy IO and is considered convenient but potentially very dangerous. The whole cottage industry of streaming monadic operators like enumeratees, pipes, conduits, io-streams, etc takes "fixing" Lazy IO as a major design goal or inspiration. Lazy IO depends upon using the function `unsafeInterleaveIO` which, as its name suggests, is considered potentially unsafe---and your example demonstrates why!
- judk 12y agoI like how the misconception is introduced by the standard library itself misnaming its own method `sequence`.
- tel 12y agoIt is sequencing—but just not in "time". It sequences in "potential dependency order". This is most clear if you look at free monads.
- sfvisser 12y agoIt's not entirely right to call this a misconception. The monadic bind is inherently sequential. The right hand side of the bind might compute a computation based on the result of the left hand side of the bind.
- sfvisser 12y agoThis isn't true. They are absolutely not the same and don't yield the same behavior for every monad/applicative pair. First, you probably meant: do x <- a y <- b return (x + y) -- not: a + b With the current desugaring of do-syntax there is no way the compiler will know that the statement 'b' doesn't have a dependency on the variable 'x' and will desugar to: a >>= \x -> b >>= \y -> return (x + y) or, maybe more legible: bind a (\x -> bind b (\y -> return (x + y)) So, even if the 'b' doesn't use 'x', it is implicitly sequential and the effects of 'a' yielding 'x' need to be done before the effects of 'b' yielding 'y'. This can be a waste, e.g. when both are network calls that can be done in parallel. The `Applicative` interfaces statically guarantees there is no data dependency and might therefor have a smarter implementation. For `Monad` this simply isn't possible. It's a subtle, but very important, difference.