4 ms·
Article says that this: readFile "foo" >>= writeFile "bar" is preferable to this: do text <- readFile "foo" writeFile "bar" text I don't
by bad_user 6y ago
Article says that this:
readFile "foo" >>= writeFile "bar"
is preferable to this:
do
text <- readFile "foo"
writeFile "bar" text
I don't agree. Even if a working knowledge of the monadic bind is required, the second expression is more readable to beginners and can be extended more easily to do other things.
Of course, the first expression is written in "pointfree" style, where the code is described as a composition of functions. Even if I like pointfree one liners that are clear (so depending on context), I hate pointfree style applied to entire codebases and I think it's one barrier for Haskell's adoption.
---
Article also says: "Newcomers might think that the order of statements determines the order of execution."
But that's good, because the order of statements in a "do" expression does determine the order of execution. That's the whole point with monads and the "do" expression. That you can get away with applicatives instead, that's another point entirely.
Note that GHC nowadays has a language extension called "ApplicativeDo". So to take an example from the article:
do x <- Just (3+5)
y <- Just (5*7)
return (x-y)
In this case you just enable "ApplicativeDo" and it will magically use applicatives without changing the code.
The order of execution on the other hand will NOT matter, so you can still pretend that there's an order to it, because such code will be pure and it will not be repurposed to run in parallel or anything crazy like that, the only thing the compiler can do in such cases is to eliminate unused expressions.
Funny thing about Applicative being a super class of Monad, but "ap" / "map2" operations need to remain consistent with "bind" by law otherwise the implementation isn't valid. So it doesn't matter if the code above uses applicatives or monads, that's just an optimization, as for all practical purposes the result should be the same, order of execution included.
Of course, code using Applicative instead of Monad is more generic, since you have less restrictions, you can work with more types and the function signatures become more clear in what they do (the more abstract they are, the less they can do), so that's the primary reason for why Applicative is recommended whenever you can get away with it. No reason to bring the Monad chainsaw to the party when not needed.
- tome 6y ago> the order of statements in a "do" expression does determine the order of execution Not really, unless you take a very specific definition for "order of execution". There are plenty of monads where order of statements is unrelated to the order of execution, Identity, for example!
- bad_user 6y agoI don't agree. Bind creates a data dependence that forces an evaluation order. do x <- f y <- g x No matter what Monad you're speaking of, in this expression "x" is going to be evaluated before "y", what we sometimes call a happens before relationship, because evaluating "y" depends on evaluating "x".
- ImprobableTruth 6y agoUnless you're using some non-standard definition of evaluation, this is not true when using a lazy strategy. Consider the term ((const c) x) for g x which reduces to c without ever evaluating x.
- tome 6y agoWhat are you basing your disagreement on? Can you explain to me in which sense "x" is evaluated before "y" in this example? {-# LANGUAGE BangPatterns #-} import Data.Functor.Identity import Debug.Trace f = let !_ = trace "Evaluating f" () in return 1 g x = let !_ = trace "Evaluating g" () in return (x + 1) example :: Int example = runIdentity $ do x <- f y <- g x return y > example Evaluating g Evaluating f 2