|
I'm generally in favour of introducing applicatives, but I don't think the code in the article is a good example: (bid, now) <- liftIO $ do
b <- randomIO
n <- getCurrentTime
return (b, n)
(bid, now) <- liftIO $ (,)
<$> randomIO
<*> getCurrentTime
The applicative code could be considered better, since it avoids one-shot variables. However, that's not the biggest smell with this code. To me, the problems are:- Constructing-then-destructing a pair; is it really necessary? - Use of `$`; is there a way to avoid having to alter the precedence? - Combining two seemingly unrelated actions into one; `randomIO` should be completely uncorrelated to the current time, so why put them in the same action? - Potential laziness issues; it looks like we're using the `(bid, now)` combination to ensure the two IO actions are executed together, but will they be? WHNF will give us `(_ , _)`; if we force `bid`, will `now` also be forced? Not saying I have answers to these, but I would say those are more "smelly" than the do-notation with a return |
Code review 1000 lines: "Looks fine"