Deriving strategy
also: deriving via, generalizednewtypederiving
An explicit choice of how a derived instance is produced: stock (compiler-generated), newtype (reuse the underlying type's instance by coercion), anyclass (take the class's own defaults), or via (borrow the instance of a representationally equal type). Naming the strategy removes the ambiguity that arises when more than one is applicable.
When more than one mechanism could generate an instance, the compiler has to pick, and for a newtype at least two are always applicable: generate the code structurally, or reuse the wrapped type's instance. Naming the strategy removes the ambiguity.
The four strategies, on one declaration.
{-# LANGUAGE DerivingStrategies, GeneralizedNewtypeDeriving, DerivingVia #-}newtype Age = Age Intderiving stock (Show, Eq) -- structural: shows as `Age 3`deriving newtype (Num, Ord) -- coerced: arithmetic is Int's, zero costderiving anyclass (ToJSON) -- the class's own default methodsderiving (Semigroup, Monoid)via (Sum Int) -- borrow the instances of a coercible type
The distinction is not cosmetic. stock Show prints Age 3 and newtype Show prints 3; via (Sum Int) makes <> addition while via (Product Int) would make it multiplication, from the same type with the same representation.
The safety condition behind newtype and via is representational equality: the coercion is free, but it is only sound when the class has no method whose type mentions the type variable in a role-incompatible position, which is what type roles exist to track.
read more