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?
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.
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
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