| Safe Haskell | Safe-Inferred |
|---|---|
| Language | GHC2021 |
Control.Monad.Trans.Elevator
Elevator
Elevator can be used to lift instances through monad transformers as long as they implement
a MonadTrans / MonadTransControl / MonadTransControlIdentity instance.
MonadTransControl is only necessary when there is atleast one method with a monadic argument.
MonadTransControlIdentity is even stronger and only required for a few specific instances.
newtype Elevator t m a Source #
A newtype wrapper for monad transformers.
Access instances of the inner monad m.
Type level arguments:
Instances
Examples
Example 1: Recover submerged instances
Let's assume you want to define a monad transformer stack.
newtype StackT m a = StackT { unStackT :: ReaderT Char (ReaderT Bool m) a }
deriving newtype (Functor, Applicative, Monad)
Now you want to expose the inner ( instance with MonadReader Bool)(StackT m).
Normally it's shadowed by the ( instance, but we can use MonadReader Char)Elevator to
access the inner transformer.
deriving (MonadReaderBool) viaElevator(ReaderTChar) (ReaderTBoolm)
Example 2: Custom transformer without boilerplate
Let's assume you have defined a monad transformer.
newtype CustomT m a = CustomT { unCustomT :: IdentityT m a }
deriving newtype (Functor, Applicative, Monad)
deriving newtype (MonadTrans, MonadTransControl)
runCustomT :: CustomT m a -> m a
runCustomT = runIdentityT . unCustomT
Now you want to use this monad transformer in a transformer stack.
newtype StackT m a = StackT { unStackT :: CustomT (ReaderT Bool m) a }
deriving newtype (Functor, Applicative, Monad)
Unfortunately we can't derive a ( instance with
GeneralizedNewtypeDeriving, without also adding the instance to Monad m => MonadReader Bool (StackT m))CustomT.
To still derive this trivial instance we can use Elevator with DerivingVia.
deriving (MonadReaderBool) via (ElevatorCustomT (ReaderTBoolm))
Example 3: Adding an instance for Elevator
Suppose you define a new type class.
class Monad m => MonadCustom m where
simpleMethod :: a -> m a
complicatedMethod :: (a -> m b) -> m b
A simple way to allow a type class to be lifted through other monad transformers is by adding an
instance for Elevator.
You have to be careful about monadic state StT, when defining such instances using
MonadTransControl.
instance (MonadCustom m,MonadTransControlt) => MonadCustom (Elevatort m) where simpleMethod =lift. simpleMethod complicatedMethod f = (restoreT.pure=<<) $liftWith$ \ runT -> complicatedMethod $ runT . f
Some useful examples (or exercises) are the instances for
mtl's type classes (MonadError, MonadReader,
MonadState, MonadWriter).