| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
Stock.Override
Description
Per-field deriving modifiers for the Stock plugin.
Override a cfg wraps a with a type-level configuration cfg that the
plugin reads while it synthesizes the instance: each entry names a field and
the modifier to run on it (per-field DerivingVia). At runtime Override is
just a (a newtype), so there is no cost.
data Coord = Coord { x :: Int, y :: Int }
deriving Semigroup
via Stock (Override Coord '[ "x" ':= Sum, "y" ':= Product ])The config is an uninterpreted, poly-kinded marker the solver decodes off the
type — never reduced. See docs/override-design.md.
Addressing a field
A field is addressed by name ("x" ':= m), by type (Int ':= m, every
Int field), or by position (). A modifier is pinned
(At Coord 0 ':= mSum Int) or broadcast to the field's own type (Sum). A whole entry
may instead be positional — one inner list per constructor, one cell per
field — where Keep (written _) leaves a field untouched:
deriving Semigroup via Stock (Override Coord '[ [Sum, Keep] ]) -- field 0 via Sum
Surface sugar (the -fplugin Stock source pass, Stock.Surface)
The honest marker form is verbose, so the same plugin lowers a quote-free
surface at parse time, scoped to Override applications:
Override Coord [ x via Sum, Coord at 0 via Sum, _ ] -- what you write Override Coord '[ "x" := Sum, At Coord 0 := Sum, Keep ] -- what the solver reads
namely: a bare lowercase selector becomes a Symbol (x ⟶ "x"), via
becomes :=, at becomes At, and a wildcard _ becomes Keep.
Higher order
Override1 / Override2 reshape the functor of a field rather than its
element type (an h a field becomes m a), so the lifted instance
(Functor, Eq1, Applicative, …) uses m's method. See Override1.
Synopsis
- newtype Override a (cfg :: k) = Override a
- type Overriding a (cfg :: k) = Stock (Override a cfg)
- newtype Override1 (f :: j -> Type) (cfg :: k) (a :: j) = Override1 (f a)
- type Overriding1 (f :: j -> Type) (cfg :: k) = Stock1 (Override1 f cfg)
- newtype Override2 (p :: Type -> Type -> Type) (cfg :: k) a b = Override2 (p a b)
- type Overriding2 (p :: Type -> Type -> Type) (cfg :: k) = Stock2 (Override2 p cfg)
- data family (sel1 :: sel) := (m :: k)
- data family (a :: k1) --> (b :: k2) :: j
- data family At (con :: kc) (pos :: Nat) :: sel
- data family Keep :: k
Documentation
newtype Override a (cfg :: k) Source #
a with a per-field override configuration cfg. A newtype, so
Coercible (Override a cfg) a; cfg is phantom (read by the plugin only).
Poly-kinded in cfg so it accepts both config shapes (see
docs/override-design.md §5a): the entry list '[ "x" ':= Sum, … ]
(cfg :: [Type]) and the positional '[ '[Sum Int, Keep, Keep] ] — one
inner list per constructor, one element per field (cfg :: [[Type]]).
Constructors
| Override a |
type Overriding a (cfg :: k) = Stock (Override a cfg) Source #
Overriding a cfg = Stock (Override a cfg) — the per-field wrapper read
through Generically. Because the plugin makes Generic honour Override
(the Rep carries the modifier field types), deriving C via Generically
(Overriding A cfg) derives any Generic-based class over A with the
per-field modifiers applied. The Generic-facing twin of using Stock +
Override directly with the built-in synthesizers.
newtype Override1 (f :: j -> Type) (cfg :: k) (a :: j) Source #
The one-parameter analogue of Override: Override1 f cfg wraps a
one-parameter constructor f for use through Stock1. Each positional
modifier m (a k -> Type) reshapes the functor of an h a field to
m a — so e.g. a [a] field becomes ZipList a and the derived
Applicative zips instead of taking the cartesian product. A newtype, so
Coercible (Override1 f cfg a) (f a).
Constructors
| Override1 (f a) |
type Overriding1 (f :: j -> Type) (cfg :: k) = Stock1 (Override1 f cfg) Source #
Overriding1 f cfg = Stock1 (Override1 f cfg) — the Stock1-facing
per-field wrapper. deriving Applicative via Overriding1 F '[ '[ZipList] ]
reshapes F's [a] field into ZipList a before deriving.
newtype Override2 (p :: Type -> Type -> Type) (cfg :: k) a b Source #
The two-parameter analogue of Override: Override2 p cfg wraps a
two-parameter constructor p for use through Stock2. Each positional
modifier m (a Type -> Type -> Type) reshapes its field to m a b — the
modifier applied to both datatype parameters — turning the field into a
per-field Category. A newtype, so Coercible (Override2 p cfg a b) (p a b).
Constructors
| Override2 (p a b) |
type Overriding2 (p :: Type -> Type -> Type) (cfg :: k) = Stock2 (Override2 p cfg) Source #
Overriding2 p cfg = Stock2 (Override2 p cfg) — the Stock2-facing
per-field wrapper. deriving Category via Overriding2 '[ '[Basic (Sum Int),
Basic String, Kleisli Maybe] ] Foo reshapes each field of Foo a b into a
Category and derives Category pointwise over them.
data family (sel1 :: sel) := (m :: k) Source #
A single config entry: the field name (a Symbol) gets modifier m.
Poly-kinded in m, so a saturated modifier (Sum Int :: Type) and an
unsaturated one (Sum :: Type -> Type) both fit; the plugin dispatches on
m's kind (pin vs. broadcast). An uninterpreted 'data family' — generative,
injective, never reduced — so the solver reads it back verbatim.
data family (a :: k1) --> (b :: k2) :: j infixr 5 Source #
A path hop: h '--> rest. Each non-terminal hop selects a node — a
promoted constructor (that constructor), a Nat (field by position) or a
Symbol (field by label) — and the terminal hop is the modifier; the
modifier applies to every field under the prefix. So 'P '--> m overrides
every field of P and 'P '--> 0 '--> m overrides only its first field
(design §4). Poly-kinded, uninterpreted, never reduced.
data family At (con :: kc) (pos :: Nat) :: sel Source #
A positional selector: field pos of constructor con. Used prefix on
the left of (:=) — At Con 0 := m — so the surface keeps a single infix
operator. Like (:=) it is an uninterpreted, poly-kinded marker.
data family Keep :: k Source #
The positional no-op modifier: a field whose slot is Keep is left at its
own type. Written _ in source (the -fplugin Stock surface pass lowers the
type wildcard to Keep), so '[ '[Sum Int, _, _] ] overrides only the first
field. Poly-kinded (a free-result-kind 'data family') so it sits in a list
beside modifiers of any kind — Sum Int :: Type or Sum :: Type -> Type —
without breaking the list's kind homogeneity. An uninterpreted marker the
plugin reads; never reduced.