Wednesday, January 19, 2011

Corrected Instances for the MonadAttempt class

In my previous post, I outlined the MonadAttempt class that I had created to solve a problem with code generation using a state monad in Haskell. This morning, with a much clearer mind, I was able to create much cleaner instances for the StateT and ErrorT monads:
instance (Monad m, MonadAttempt m) => MonadAttempt (StateT s m) where
  attempt a m = do s <- get
                   lift $ attempt a $ do (x, _) <- runStateT m s
                                         return x
 
instance (Error e, Monad m, MonadAttempt m) => MonadAttempt (ErrorT e m) where
  attempt a m = lift $ attempt a $ do e <- runErrorT m
                                      case e of
                                        Left _ -> return a
                                        Right x -> return x


  

2 comments:

  1. You can improve your MonadState some more using the 'evalStateT' function instead of 'runStateT'; it only returns the final value of the computation and not the final state.

    attempt a m = get >>= lift . attempt a . evalStateT m

    (The point-free version comes naturally when doing this change).

    Similarly, using the 'either' function you can improve the MonadError instance:

    attempt a m = lift . attempt a $ either (const a) id `liftM` runErrorT m

    Have fun!

    ReplyDelete
  2. Thanks! I forgot about that function when I went to write these. That is indeed much nicer.

    ReplyDelete

Comments are moderated. I will try to get to them quickly. Off-topic or obscene comments, name-calling, and destructive criticism will all vanish into the void.

Disagree with me all you want, but keep it respectful towards me and everyone else.