A monad transformer stack will provide access to many monad type classes. But you have to be careful, which transformers can be stacked.
derivingtrans uses 3 categories of monad transformers to implement instances for any monad transformer without knowing its exact definition, which solves mtl's “n^{2} problem”.
MonadTrans

lift
a monadic computationm a
into a monad transformert m a
. MonadTransControl

liftWith
runs a transformer’s computationt m a
in the base monadm a
, but you have to take care of the transformer’s monadic stateStT t a
explicitly withrestoreT
. MonadTransControlIdentity

liftWithIdentity
is just likeliftWith
, but without monadic state.
These 3 categories form a hierarchy where MonadTransControlIdentity
is stronger than MonadTransControl
, which is stronger than MonadTrans
.
Compatibility Matrix
The following table gives you two pieces of information. The “transformer category” tells you, which kind of transformer you can stack on top and still keep access to the type class. The “set by transformers” column tells you, which transformers implement the type class by themselves.
Note

This table is valid for derivingtrans 0.8.0.0. 
monad type class  transformer category  set by transformers  



set by base monad 



set by base monad 



set by base monad 

base 












set by base monad 







exceptions 







mtl 































primitive 


set by base monad 
random 









resourcet 



unliftio 


set by base monad 
And now let me quickly explain how to make use of this table with an example.
MonadReader r
as an example.In the table you will find a row on MonadReader
, which will give you the following information.
A
MonadReader r m
instance can also implyMonadReader r (t m)
whent
satisfiesMonadTransControl
.
ReaderT r
orRWST r w s
can be used to implement an instance by themselves.
Here are some examples of transformer stacks for any Monad m
using (.>)
from derivingtrans.
(TransparentT .> ReaderT r .> ExceptT e) m


✓ will have a
MonadReader r
instance, becauseExceptT e
satisfiesMonadTransControl
.

(TransparentT .> ReaderT r .> ContT r) m


❏ won’t have a
MonadReader r
instance, becauseContT r
doesn’t satisfyMonadTransControl
.

(TransparentT .> ReaderT r1 .> ReaderT r2) m


✓ will have a
MonadReader r2
instance. 
✓ will also have a
MonadReader r1
instance, unlessr1 ~ r2
.

(TransparentT .> ExceptT e) m


will have a
MonadReader r
instance, wheneverm
satisfiesMonadReader r
.

Feel free to use this table as a cheat sheet or learning material. There are some intricacies though, which are hard to express in this format.
Tip

Some methods like 
Note

Some monad type classes are “set by base monad”.
I chose this for a few type classes, which only make sense when the instances come from the base monad Compare these instances to understand the difference.

Outlook
Currently I don’t have proofs for the compatibility matrix, so it’s possible, that some instances are not lawful and will change in the future.
I am working on supporting logict, but in this case I am not yet sure, whether we are allowed to lift it through any t
satisfying MonadTransControl
.