.. _deriving-via:
Deriving via
------------
.. extension:: DerivingVia
:shortdesc: Enable deriving instances ``via`` types of the same runtime
representation.
Implies :extension:`DerivingStrategies`.
:implies: :extension:`DerivingStrategies`
:since: 8.6.1
This allows ``deriving`` a class instance for a type by specifying
another type that is already an instance of that class.
This only makes sense if the methods have identical runtime representations,
in the sense that coerce (see The ``Coercible`` constraint) can convert
the existing implementation into the desired implementation.
The generated code will be rejected with a type error otherwise.
:extension:`DerivingVia` is indicated by the use of the ``via``
deriving strategy. ``via`` requires specifying another type (the ``via`` type)
to ``coerce`` through. For example, this code: ::
{-# LANGUAGE DerivingVia #-}
import Numeric
newtype Hex a = Hex a
instance (Integral a, Show a) => Show (Hex a) where
show (Hex a) = "0x" ++ showHex a ""
newtype Unicode = U Int
deriving Show
via (Hex Int)
-- >>> euroSign
-- 0x20ac
euroSign :: Unicode
euroSign = U 0x20ac
Generates the following instance ::
instance Show Unicode where
show :: Unicode -> String
show = Data.Coerce.coerce
@(Hex Int -> String)
@(Unicode -> String)
show
This extension generalizes :extension:`GeneralizedNewtypeDeriving`. To
derive ``Num Unicode`` with GND (``deriving newtype Num``) it must
reuse the ``Num Int`` instance. With ``DerivingVia``, we can explicitly
specify the representation type ``Int``: ::
newtype Unicode = U Int
deriving Num
via Int
deriving Show
via (Hex Int)
euroSign :: Unicode
euroSign = 0x20ac
Code duplication is common in instance declarations. A familiar
pattern is lifting operations over an ``Applicative`` functor.
Instead of having catch-all instances for ``f a`` which overlap
with all other such instances, like so: ::
instance (Applicative f, Semigroup a) => Semigroup (f a) ..
instance (Applicative f, Monoid a) => Monoid (f a) ..
We can instead create a newtype ``App``
(where ``App f a`` and ``f a`` are represented the same in memory)
and use :extension:`DerivingVia` to explicitly enable uses of this
pattern: ::
{-# LANGUAGE DerivingVia, DeriveFunctor, GeneralizedNewtypeDeriving #-}
import Control.Applicative
newtype App f a = App (f a) deriving newtype (Functor, Applicative)
instance (Applicative f, Semigroup a) => Semigroup (App f a) where
(<>) = liftA2 (<>)
instance (Applicative f, Monoid a) => Monoid (App f a) where
mempty = pure mempty
data Pair a = MkPair a a
deriving stock
Functor
deriving (Semigroup, Monoid)
via (App Pair a)
instance Applicative Pair where
pure a = MkPair a a
MkPair f g <*> MkPair a b = MkPair (f a) (g b)
Note that the ``via`` type does not have to be a ``newtype``.
The only restriction is that it is coercible with the
original data type. This means there can be arbitrary nesting of newtypes,
as in the following example: ::
newtype Kleisli m a b = Kleisli (a -> m b)
deriving (Semigroup, Monoid)
via (a -> App m b)
Here we make use of the ``Monoid ((->) a)`` instance.
When used in combination with :extension:`StandaloneDeriving` we swap the order
for the instance we base our derivation on and the instance we define e.g.: ::
deriving via (a -> App m b) instance Monoid (Kleisli m a b)