monad-peel-0.1: Lift control operations like exception catching through monad transformers

MaintainerAnders Kaseorg <>



This module defines the class MonadTransPeel of monad transformers through which control operations can be lifted. Instances are included for all the standard monad transformers from the transformers library except ContT.

idPeel and liftPeel are provided to assist creation of MonadPeelIO-like classes (see Control.Monad.IO.Peel) based on core monads other than IO.



class MonadTrans t => MonadTransPeel t whereSource

MonadTransPeel is the class of monad transformers supporting an extra operation peel, enabling control operations (functions that use monadic actions as input instead of just output) to be lifted through the transformer.


peel :: (Monad m, Monad n, Monad o) => t n (t m a -> m (t o a))Source

peel is used to peel off the outer layer of a transformed monadic action, allowing an transformed action t m a to be treated as a base action m b.

More precisely, peel captures the monadic state of t at the point where it is bound (in t n), yielding a function t m a -> m (t o a); this function runs a transformed monadic action t m a in the base monad m using the captured state, and leaves the result t o a in the monad m after all side effects in m have occurred.

This can be used together with lift to lift control operations with types such as M a -> M a into the transformed monad t M:

    instance Monad M
    foo :: M a -> M a
    foo' :: (MonadTransPeel t, Monad (t M)) => t M a -> t M a
    foo' a = do
      k <- peel  -- k :: t M a -> M (t M a)
      join $ lift $ foo (k a)  -- uses foo :: M (t M a) -> M (t M a)

peel is typically used with m == n == o, but is required to be polymorphic for greater type safety: for example, this type ensures that the result of running the action in m has no remaining side effects in m.

idPeel :: (Monad m, Monad n, Monad o) => n (m a -> m (o a))Source

idPeel acts as the "identity" peel operation from a monad m to itself.

    idPeel = return $ liftM return

It serves as the base case for a class like MonadPeelIO, which allows control operations in some base monad (here IO) to be lifted through arbitrary stacks of zero or more monad transformers in one call. For example, Control.Monad.IO.Peel defines

    class MonadIO m => MonadPeelIO m where
      peelIO :: m (m a -> IO (m a))
    instance MonadPeelIO IO where
      peelIO = idPeel

liftPeel :: (MonadTransPeel t, Monad m, Monad m', Monad n', Monad (t n'), Monad o', Monad (t o')) => n' (m' (t o' a) -> m (o' (t o' a))) -> t n' (t m' a -> m (t o' a))Source

liftPeel is used to compose two peel operations: the outer provided by a MonadTransPeel instance, and the inner provided as the argument.

It satisfies liftPeel idPeel == peel.

It serves as the induction step of a MonadPeelIO-like class. For example, Control.Monad.IO.Peel defines

    instance MonadPeelIO m => MonadPeelIO (StateT s m) where
      peelIO = liftPeel peelIO

using the MonadTransPeel instance of StateT s.