[Haskell-cafe] Inverting a Monad

Bas van Dijk v.dijk.bas at gmail.com
Wed Feb 6 16:47:33 EST 2008


On Feb 6, 2008 8:27 PM, Tillmann Rendel
<rendel at rbg.informatik.tu-darmstadt.de> wrote:
> What about this?
>
> inv :: MonadError e m => m a -> m ()
> inv m = join $ (m >> return mzero) `catchError` \_ -> return (return ())

Beautiful! That's the one I'm looking for!


I was already defining a 'MonadInvert' class and a bunch of instances
like below but this is a much more flexible solution.

-------------------------------------------------------------------------------------------------
-- | A Monad that supports inversion.
-- Turning success into failure and failure into success.
class Monad m => MonadInvert m where
    -- | @invert m@ fails when @m@ is successfull (returns a value)
    -- and returns @()@ when @m@ fails .
    invert :: m a -> m ()

instance MonadInvert Maybe where
    invert Nothing  = Just ()
    invert (Just _) = Nothing

instance MonadInvert [] where
    invert []    = [()]
    invert (_:_) = []

instance E.Error e => MonadInvert (Either e) where
    invert (Left _)  = Right ()
    invert (Right _) = Left E.noMsg

instance (E.Error e, MonadInvert m) => MonadInvert (E.ErrorT e m) where
    invert = T.lift . invert . E.runErrorT

instance MonadInvert m => MonadInvert (S.StateT st m) where
    invert m = S.StateT $ \s -> (invert $ S.runStateT m s) >>= \u ->
return (u, s)

...

-------------------------------------------------------------------------------------------------

Thanks very much.

Bas


More information about the Haskell-Cafe mailing list