# Composing instances using `deriving via`

Today I watched the very good, and short, video from Tweag on how to Avoid boilerplate instances with -XDerivingVia. It made me realise that I've read about this before, but then the topic was on reducing boilerplate with MTL-style code.

Given that I'd forgotten about it I'm writing this mostly as a note to myself.

## The example from the Tweag video, slightly changed

The code for making film ratings into a `Monoid`

, when translated to the UK,
would look something like this:

{-# LANGUAGE DerivingVia #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} module DeriveMonoid where newtype Supremum a = MkSup a deriving stock (Bounded, Eq, Ord) deriving newtype (Show) instance Ord a => Semigroup (Supremum a) where (<>) = max instance (Bounded a, Ord a) => Monoid (Supremum a) where mempty = minBound data FilmClassification = Universal | ParentalGuidance | Suitable12 | Suitable15 | Adults | Restricted18 deriving stock (Bounded, Eq, Ord) deriving (Monoid, Semigroup) via (Supremum FilmClassification)

## Composing by deriving

First let's write up a silly class for writing to `stdout`

, a single operation will do.

class Monad m => StdoutWriter m where writeStdoutLn :: String -> m ()

Then we'll need a type to attach the implementation to.

newtype SimpleStdoutWriter m a = SimpleStdoutWriter (m a) deriving (Functor, Applicative, Monad, MonadIO)

and of course an implementation

instance MonadIO m => StdoutWriter (SimpleStdoutWriter m) where writeStdoutLn = liftIO . putStrLn

Now let's create an app environment based on `ReaderT`

and use `deriving via`

to
give it an implementation of `StdoutWriter`

via `SimpleStdoutWriter`

.

newtype AppEnv a = AppEnv {unAppEnv :: ReaderT Int IO a} deriving ( Functor , Applicative , Monad , MonadIO , MonadReader Int ) deriving (StdoutWriter) via (SimpleStdoutWriter AppEnv)

Then a quick test to show that it actually works.

λ> runReaderT (unAppEnv $ writeStdoutLn "hello, world!") 0 hello, world!