sequence : [IO a] -> IO [a]
sequence [] = return []
sequence (c:cs) = do
x <- c
xs <- cs
return (x:xs)
All we wanted to do was apply a pure function (:)
to simple values like x
& xs
which were trapped under a command/monad.
Introducing ap
:
ap: m (a -> b) -> m a -> m b
ap cf cx = do
f <- cf
x <- cx
return f x
Now,
sequence (c: cs) = return (:) `ap` c `ap` (sequence cs)
or replace return
with pure
and ap
with <$>
sequence (c: cs) = pure (:) <$> c <$> (sequence cs)
Furthermore,
replace: pure f <$> u1 <$> u2 ...
with: | f u1 u2 ... |
(syntactic replacement with | ... |
)
And so,
sequence (c:cs) = | (:) c (sequence cs) |
See how result follows input form!!!
Another,
add : Expr -> Expr -> Expr
add expr1 expr2 = | (+) expr1 expr2 |
-- where Expr = ... some monadic expression like (Val Int | Add Expr Expr)
again see how result follows input form!!!
All of this being syntactic by replacing:
pure f <$> u1 <$> u2 ...
with:
| f u1 u2 ... |
back to original form:
sequence (c:cs) = pure (:) <$> c <$> (sequence cs)
add expr1 expr1 = pure (+) expr1 <$> expr2