Deriving Strategies, Generics and Coercible

Roles (type role, nominal/representational/phantom) control where coerce is allowed, which keeps invariants (e.g., Map k v's key ordering) safe.

{-# LANGUAGE DerivingStrategies, DerivingVia, DeriveAnyClass, GeneralizedNewtypeDeriving, DeriveGeneric #-}
import GHC.Generics (Generic)
import Data.Monoid (Sum (..))
import Data.Aeson (ToJSON, FromJSON)

newtype Age = Age Int
  deriving stock (Show)                      -- standard deriving
  deriving newtype (Eq, Ord, Num)            -- reuse Int's instances (GND)

newtype Score = Score Int
  deriving (Semigroup, Monoid) via (Sum Int) -- DerivingVia: borrow another type's instance

data User = User {userName :: String, userAge :: Int}
  deriving stock (Show, Eq, Generic)
  deriving anyclass (ToJSON, FromJSON)       -- empty instances using Generic defaults

-- Standalone deriving
data Point = Point Int Int
deriving stock instance Show Point

-- Coercible: zero-cost conversion between representationally equal types
import Data.Coerce (coerce)
ages :: [Age]
ages = coerce [30, 25 :: Int]                -- no runtime traversal

-- GHC.Generics: write functions generic over the structure of data types
-- (used by aeson, binary, hashable, QuickCheck's generic-arbitrary, deepseq...)