[Haskell-cafe] Stacking monads
Tillmann Rendel
rendel at daimi.au.dk
Fri Oct 3 21:16:20 EDT 2008
Andrew Coppin wrote:
> run_or s0 x y =
> let
> either_rset1 = sequence $ run s0 x
> either_rset2 = sequence $ run s0 y
> either_rset3 = do rset1 <- either_rset1; rset2 <- either_rset2;
> return (merge rset1 rset2)
> in case either_rset3 of
> Left e -> throwError e
> Right rset -> lift rset
Just to expand on that discussion of Control.Monad.ap aka.
(Control.Applicative.<*>) in the other half of the thread. The expression
do rset1 <- either_rset1
rset2 <- either_rset2
return (merge rset1 rset2)
follows exactly the pattern Applicative is made for: We execute some
actions, and combine their result using a pure function. Which action we
execute is independent from the result of the previous actions. That
means that we can write this expression as:
return merge `ap` either_rset1 `ap` either_rset2
Note how we avoid to give names to intermediate results just to use them
in the very next line. Since return f `ap` x == f `fmap` x, we can write
shorter
merge `fmap` either_rset1 `ap` either_rset2
Or in Applicative style:
merge <$> either_rset1 <*> either_rset2
Now that the expression is somewhat shorter, we can inline the
either_rset1, 2 and 3 as follows:
case merge <$> sequence (run s0 x) <*> sequence (run s0 y) of
Left e -> throwError e
Right rset -> lift rset
Note how the structure of the code reflects what happens. The structure
is merge <$> ... <*> ..., and the meaning is: merge is called on two
arguments, which are created by running some actions, and the result is
again an action.
While we are one it, we can get rid of the pattern matching by employing
the either function as follows:
either throwError lift (merge <$> sequence (run s0 x) <*> sequence
(run s0 y))
> Do you realise, this single snippet of code utilises the ErrorT monad [transformer], the ResultSet monad, *and* the Either monad, all in the space of a few lines?? That's three monads in one function! o_O
Now it fits on a single line!
Tillmann
More information about the Haskell-Cafe
mailing list