Consider this example:
{-# language ApplicativeDo #-}
module X where
data Tuple a b = Tuple a b deriving Show
instance Functor (Tuple a) where
fmap f (Tuple x y) = Tuple x (f y)
instance Foldable (Tuple a) where
foldr f z (Tuple _ y) = f y z
instance Traversable (Tuple a) where
traverse f (Tuple x y) = do
y' <- f y
let t' = Tuple x y'
return $ t'
Looks nice! But no:
[1 of 1] Compiling X ( X.hs, interpreted )
X.hs:15:9: error:
• Could not deduce (Monad f) arising from a do statement
from the context: Applicative f
bound by the type signature for:
traverse :: forall (f :: * -> *) a1 b.
Applicative f =>
(a1 -> f b) -> Tuple a a1 -> f (Tuple a b)
at X.hs:14:5-12
Possible fix:
add (Monad f) to the context of
the type signature for:
traverse :: forall (f :: * -> *) a1 b.
Applicative f =>
(a1 -> f b) -> Tuple a a1 -> f (Tuple a b)
• In a stmt of a 'do' block: y' <- f y
In the expression:
do y' <- f y
let t' = Tuple x y'
return $ t'
In an equation for ‘traverse’:
traverse f (Tuple x y)
= do y' <- f y
let t' = ...
return $ t'
|
15 | y' <- f y
| ^^^^^^^^^
Failed, no modules loaded.
Even this fails:
instance Traversable (Tuple a) where
traverse f (Tuple x y) = do
y' <- f y
let unrelated = 1
return $ Tuple x y'
So, introducing any let statement removes the "applicative" from the "applicative do". Why?
It would translate into
let unrelated = 1 in return $ Tuple x y'
which doesn't have the form return <something>, and applicative do requires the last statement to be a return or pure:
In general, the rule for when a do statement incurs a
Monadconstraint is as follows. If the do-expression has the following form:do p1 <- E1; ...; pn <- En; return Ewhere none of the variables defined by
p1...pnare mentioned inE1...En, andp1...pnare all variables or lazy patterns, then the expression will only requireApplicative. Otherwise, the expression will requireMonad. The block may return a pure expressionEdepending upon the resultsp1...pnwith eitherreturnorpure.Note: the final statement must match one of these patterns exactly:
return E return $ E pure E pure $ Eotherwise GHC cannot recognise it as a return statement, and the transformation to use
<$>that we saw above does not apply. In particular, slight variations such asreturn . Just $ xorlet x = e in return xwould not be recognised.
If you look at the description of desugaring in https://gitlab.haskell.org/ghc/ghc/wikis/applicative-do, it also doesn't support let in any way.
What applicative expression would you like this to desugar to? A monadic expression is a series of chained scopes, so it makes sense for a let to introduce a binding that extends over all the remaining scopes, but with applicative the various expressions can't really depend on each other, so there's no scope that it makes sense to desugar the let into.
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