When I am using Functors, Monads, and other Hakell constructs, if my code is more than just a couple of lines, I prefer using some syntactic sugar like do-notation. This makes it easier for me to follow the flow of the code. Outside of stylistic preference, is there any real advantage in using de-sugared blocks as opposed to the sugared alternative?
I think it's a shame that people are treating this question as dumb, especially because contrary to the strongest opinions being expressed here, the answer is yes, there can be an advantage to avoiding the do-sugar. Simon Marlow gives an excellent example of this in his talk about the Facebook Haxl project that he's working on. Here's a short, undoubtedly butchered version -- definitely look at his slides for more details!
Here's an example of a query Facebook might want to run:
numCommonFriends x y = do
fx <- friendsOf x
fy <- friendsOf y
return (length (intersect fx fy))
With the sugar, this is beautiful. Unfortunately, it's also badly sequential. It turns out you can design a Monad that makes the above possible, but badly underperformant, and the following non-sugary Applicative version significantly more performant:
numCommonFriends x y = length <$> liftA2 intersect (friendsOf x) (friendsOf y)
The point here being that the Applicative instance gets to run both friendsOf branches at once: it is statically clear that the second call to friendsOf
cannot depend on the first. This is a feat that monadic bind can't duplicate because the action computed in bind's second argument could depend on the result of the computation in the first argument.
Designing a new kind of sugar that allows such optimizations is an active research question at the moment, as far as I know.
Well no. The whole point of sugaring is that it desugars to exactly the desugared version, so there can't be any non-stylistic advantage. It might be good for you to get used to the desugared notation so that you can follow it when it is stylistically clearer, but you won't get any performance benefits or anything, because the code is identical.
Daniel argues for desugaring from a performance standpoint, amalloy argues against desugaring from a readability standpoint.
I'd argue that sometimes, the desugared version is just more readable i.e. compare
echo :: IO ()
echo = do
ln <- getLine
putStrLn ln
to
echo :: IO ()
echo = putStrLn =<< getLine
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With