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?

_______________________________________________
Haskell-Cafe mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to