[Haskell-cafe] Stacking monads
Andrew Coppin
andrewcoppin at btinternet.com
Thu Oct 2 13:18:19 EDT 2008
Consider the following beautiful code:
run :: State -> Foo -> ResultSet State
run_and :: State -> Foo -> Foo -> ResultSet State
run_and s0 x y = do
s1 <- run s0 x
s2 <- run s1 y
return s2
run_or :: State -> Foo -> Foo -> ResultSet State
run_or s0 x y = merge (run s0 x) (run s0 y)
That works great. Unfortunately, I made some alterations to the
functionallity the program has, and now it is actually possible for
'run' to fail. When this happens, a problem should be reported to the
user. (By "user" I mean "the person running my compiled application".)
After an insane amount of time making my head hurt, I disocvered that
the type "Either ErrorType (ResultSet State)" is actually a monad. (Or
rather, a monad within a monad.) Unfortunately, this causes some pretty
serious problems:
run :: State -> Foo -> Either ErrorType (ResultSet State)
run_or :: State -> Foo -> Foo -> Either ErrorType (ResultSet State)
run_or s0 x y = do
rset1 <- run s0 x
rset2 <- run s1 y
return (merge rset1 rset2)
run_and :: State -> Foo -> Foo -> Either ErrorType (ResultSet State)
run_and s0 x y = run s0 x >>= \rset1 -> rset1 >>= \s1 -> run s1 y
The 'run_or' function isn't too bad. However, after about an hour of
trying, I cannot construct any definition for 'run_and' which actually
typechecks. The type signature for (>>=) requires that the result monad
matches the source monad, and there is no way for me to implement this.
Since ResultSet *just happens* to also be in Functor, I can get as far as
run_and s0 x y = run s0 x >>= \rset1 -> fmap (\s1 -> run s1 y) rset1
but that still leaves me with a value of type ResultSet (Either
ErrorType (ResultSet State)) and no obvious way to fix this.
At this point I am sorely tempted to just change ResultSet to include
the error functionallity I need. However, ResultSet is *already* an
extremely complicated monad that took me weeks to get working
correctly... I'd really prefer to just layer error handling on the top.
But I just can't get it to work right. It's soooo fiddly untangling the
multiple monads to try to *do* any useful work.
Does anybody have any idea how this whole monad stacking craziness is
*supposed* to work?
More information about the Haskell-Cafe
mailing list