Lift error value to ErrorT monad transformer

Go To StackoverFlow.com

5

I think I'm missing some basic understanding of monad transformers, because I found myself writing this code:

import Control.Monad.Identity
import Control.Monad.Error

liftError :: Either String Int -> ErrorT String Identity Int
liftError x = do case x of
                    Right val -> return val
                    Left err -> throwError err

gateway :: Bool -> ErrorT String Identity Int
gateway = liftError . inner

inner :: Bool -> Either String Int
inner True = return 5
inner False = throwError "test"

While this works, I think that this could be done more elegantly. In particular, I'm looking for a replacement of liftError, which I think I shouldn't have to define for myself.

What would be the most straightforward way to make gateway and inner work together without changing their type?

2012-04-04 17:58
by Niklas B.


6

If you just change the types a little, you don't have to do any lifting at all.

{-# LANGUAGE FlexibleContexts #-}

gateway :: Bool -> ErrorT String Identity Int
gateway = inner

inner :: MonadError String m => Bool -> m Int
inner True = return 5
inner False = throwError "test"

MonadError has instances for both ErrorT and Either, so this way you can use inner as both.

2012-04-04 18:10
by hammar
Okay, so to be more specific, I have to write a manual lifting function if I want to leave the types as they are? This is just for my understanding. BTW unfortunately I can't vote anymore today :/ You will get the vote tomorrow : - Niklas B. 2012-04-04 18:13
Without changing the types, you can use ErrorT . return in place of your liftError function. You could also use the more general version internally and only expose a copy of inner with the restricted type - hammar 2012-04-04 18:23
That ErrorT . return was exactly what I was looking for. As I mentioned, this has nothing to do with any real code, I just want to understand the concept of monad transformers : - Niklas B. 2012-04-04 18:25
Ads