Safe Haskell | None |
---|---|
Language | Haskell2010 |
Elevator
Elevator
can be used to lift instances through monad transformers as long as they implement
MonadTrans
and MonadTransControl
instances.
MonadTransControl
is only necessary when there is atleast one method with a monadic argument.
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 (MonadReader
Bool
) viaElevator
(ReaderT
Char
) (ReaderT
Bool
m)
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 (MonadReader
Bool
) via (Elevator
CustomT (ReaderT
Bool
m))
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,MonadTransControl
t) => MonadCustom (Elevator
t 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
).