Applicative do. Philippa Cowderoy's idea, some explanations due Edward Kmett
Pointful version of Language.Haskell.Meta.QQ.Idiom. Note the only expression which has the bound variables in scope is the last one.
This lets you work with applicatives without the order of fields in an data constructor becoming such a burden.
In a similar role as
fail in do notation, if match failures can be
expected, the result is an
Applicative f => f (Maybe a), rather than
Applicative f => f a, where
a may be partially defined.
ghci> [$ado| a <- "foo"; b <- "bar"; (a,b) |] [('f','b'),('f','a'),('f','r'),('o','b'),('o','a'),('o','r'),('o','b'),('o','a'),('o','r')]
ghci> [$ado| Just a <- [Just 1,Nothing,Just 2]; b <- "fo"; (a,b) |] [Just (1,'f'),Just (1,'o'),Nothing,Nothing,Just (2,'f'),Just (2,'o')]
Notice that the last statement is not of an applicative type, so when translating
from monadic do, drop the final
(do x <- [1,2,3]; return (x + 1)) == [$ado| x <- [1,2,3]; x + 1 |]
ado that does not implicitly add a Maybe when patterns may fail:
ghci> [$ado'| Just a <- [Just 1,Nothing,Just 2]; b <- "fo"; (a,b) |] [(1,'f'),(1,'o'),*** Exception: <interactive>:...
If you use patterns that may fail:
foo :: Applicative f => f (Maybe T) foo = [$ado| x:xs <- foo bar baz Just y <- quux quaffle T x y |]
ado desugars to:
foo = (\x y -> case (x,y) of (x:xs,Just y) -> Just $ T x y _ -> Nothing ) <$> foo bar baz <*> quux quaffle
ado' desugars to the less safe:
foo = (\(x:xs) (Just y) -> T x y) <$> foo bar baz <*> quux quaffle
newtype A = A Int foo :: Applicative f => f T foo = [$ado| ~(x:xs) <- foo bar baz A y <- quux quaffle T x y |]
foo = (\ ~(x:xs) (A y) -> T x y) <$> foo bar baz <*> quux quaffle
Template Haskell is currently unable to reliably look up constructor names
just from a string: if there is a type with the same name, it will
return information for that instead. This means that the safe version of
ado is prone to failure where types and values share names. It tries to
make a "best guess" in the common case that type and constructor have the
same name, but has nontrivial failure modes. In such cases,
work fine: at a pinch, you can bind simple variables with it and case-match
on them in your last statement.