The MonadTrans
document says:
Each monad transformer also comes with an operation runXXX to unwrap the transformer, exposing a computation of the inner monad.
So I wonder why MonadTrans
is not defined as
class MonadTrans t where
type p :: *
type r :: * -> *
lift:: Monad m => m a -> t m a
run :: t m a -> p -> m (r a)
to eliminate the above clause? Is that the above definition not generic enough? If so, which monad transformer does not fit for this definition?
UPDATE
Adjusted a little bit to enable different result type.
There is no universal interface for running monad transformers. For example, try running LogicT
or ContT
or FreeT
using your interface.
Even if you could generalize your interface to handle all of these example, you would still be missing the key ingredient: laws. Type class methods should obey equations that allow you to reason about code that uses the type class interface without consulting the source of specific instances. For example, the lift
method from MonadTrans
must obey these to laws:
lift (return x) = return x
lift (m >>= f) = lift m >>= \x -> lift (f x)
There are nice theoretical reasons why lift
should obey these laws, which become more apparent if you write the laws in this point-free style:
(lift .) return = return -- fmap id = id
(lift .) (f >=> g) = (lift .) f >=> (lift .) g -- fmap (f . g) = fmap f . fmap g
In other words, (lift .)
is a functor between two kleisli categories and lift
is therefore a monad morphism.
A lot of thought goes into defining type classes like Functor
, Monad
, and MonadTrans
, and the Typeclassopedia is a great place to start learning more about this topic.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With