
As it stands, working with newtypes around transformers can be kind of a pain. For example, consider newtype FreshT m a = { unFreshT :: StateT Int m a } deriving (Functor, Applicative, Monad, MonadReader r, ...) Right now, we can't just GND the instance: instance (MonadState s m) => MonadState s (FreshT m) However, the instance we end up writing is completely formulaic. Fortunately, we can solve this by using the recently added -XDerivingVia newtype Inner (t :: (* -> *) -> * -> *) m a = Inner { getInner :: t m a } deriving (Functor, Applicative, Monad) instance (MonadState s m) => MonadState s (Inner (StateT s') m) where get = Inner $ lift get put = Inner . lift . put This lets us derive the instance that we were looking for newtype FreshT m a = FreshT { unFreshT :: StateT Int m a } deriving newtype (Functor, Applicative, Monad, MonadReader r) deriving (MonadState s) via Inner (StateT Int) m This can be extended to other transformers/classes very easily. It also works well when dealing with newtyped transformer stacks. newtype FooT s e m a = FooT { unFooT :: StateT s (WriterT String (ExceptT e m)) a } deriving newtype (Functor, Applicative, Monad, MonadError e) deriving (MonadWriter w) via (StateT s (Inner (WriterT String) (ExceptT e m))) deriving (MonadState s') via Inner (StateT s) (WriterT String (ExceptT e m)) Cheers, Reed Mullanix