generic-data-1.1.0.2: Deriving instances with GHC.Generics and related utilities

Safe Haskell | None
Language | Haskell2010

Generic.Data.Microsurgery

Contents

- Surgeries with generic-lens
- Deriving via
- Synthetic types
- Microsurgeries
  - Renaming of fields and constructors
    - Renaming functions
  - Wrap every field in a type constructor
  - Substitute a generic representation from another type
  - Type aging ("denewtypify")
  - Derecordify

Description

Simple operations on generic representations: modify `Generic` instances to tweak the behavior of generic implementations as if you had declared a slightly different type.

This module provides the following microsurgeries:

- `RenameFields`: rename the fields of a record type.
- `RenameConstrs`: rename the constructors.
- `OnFields`: apply a type constructor `f :: Type -> Type` to every field.
- `CopyRep`: use the generic representation of another type of the same shape.
- `Typeage`: treat a `newtype` as a `data` type.
- `Derecordify`: treat a type as if it weren't a record.

More complex surgeries can be found in generic-data-surgery but also, perhaps surprisingly, in generic-lens (read more about this just below) and one-liner.

Surgeries can be used:

- to derive type class instances with the `DerivingVia` extension, using the `Surgery` or `ProductSurgery` type synonyms (for classes with instances for `Generically` or `GenericProduct`);
- with the `Data` "synthetic type" for more involved transformations, for example using lenses in the next section.

Synopsis

- type Surgery s a = Generically (Surgery' s a)
- type ProductSurgery s a = GenericProduct (Surgery' s a)
- type Surgeries (s :: [Type]) a = Surgery (Cat s) a
- type ProductSurgeries (s :: [Type]) a = ProductSurgery (Cat s) a
- newtype Surgery' s a = Surgery' {
  - unSurgery' :: a
  }
- type family GSurgery s (f :: k -> Type) :: k -> Type
- newtype Generically a = Generically a
- newtype GenericProduct a = GenericProduct a
- data Data (r :: Type -> Type) p
- toData :: Generic a => a -> Data (Rep a) p
- fromData :: Generic a => Data (Rep a) p -> a
- onData :: forall (r :: Type -> Type) (s :: Type -> Type) p x y. (UnifyRep r s, UnifyRep s r) => p (Data r x) (Data s y) -> p (Data r x) (Data s y)
- data RenameFields rnm
- renameFields :: forall rnm (f :: Type -> Type) p. Coercible (GSurgery (RenameFields rnm) f) f => Data f p -> Data (GSurgery (RenameFields rnm) f) p
- unrenameFields :: forall rnm (f :: Type -> Type) p. Coercible (GSurgery (RenameFields rnm) f) f => Data f p -> Data (GSurgery (RenameFields rnm) f) p
- data RenameConstrs rnm
- renameConstrs :: forall rnm (f :: Type -> Type) p. Coercible (GSurgery (RenameConstrs rnm) f) f => Data f p -> Data (GSurgery (RenameConstrs rnm) f) p
- unrenameConstrs :: forall rnm (f :: Type -> Type) p. Coercible (GSurgery (RenameConstrs rnm) f) f => Data f p -> Data (GSurgery (RenameConstrs rnm) f) p
- type family f @@ (s :: Symbol) :: Symbol
- data SId
- data SError
- data SConst (s :: Symbol)
- data SRename (xs :: [(Symbol, Symbol)]) f
- data OnFields (f :: Type -> Type)
- type DOnFields (f :: Type -> Type) a = Data (GSurgery (OnFields f) (Rep a)) ()
- data OnField (s :: Symbol) (f :: Type -> Type)
- type (%~) = OnField
- data Cat (ss :: [Type])
- type DCat (ss :: [Type]) a = Data (GSurgery (Cat ss) (Rep a)) ()
- data CopyRep a
- copyRep :: forall a (f :: Type -> Type) p. Coercible (GSurgery (CopyRep a) f) f => Data f p -> Data (GSurgery (CopyRep a) f) p
- uncopyRep :: forall a (f :: Type -> Type) p. Coercible f (GSurgery (CopyRep a) f) => Data (GSurgery (CopyRep a) f) p -> Data f p
- data Typeage
- typeage :: forall (f :: Type -> Type) p. Coercible (GSurgery Typeage f) f => Data f p -> Data (GSurgery Typeage f) p
- untypeage :: forall (f :: Type -> Type) p. Coercible f (GSurgery Typeage f) => Data (GSurgery Typeage f) p -> Data f p
- data Derecordify
- derecordify :: forall (f :: Type -> Type) p. Coercible (GSurgery Derecordify f) f => Data f p -> Data (GSurgery Derecordify f) p
- underecordify :: forall (f :: Type -> Type) p. Coercible f (GSurgery Derecordify f) => Data (GSurgery Derecordify f) p -> Data f p

# Surgeries with generic-lens

One common and simple situation is to modify the type of some fields, for example wrapping them in a newtype.

We can leverage the `generic-lens` library, with the two functions below.

    -- Lens to a field named fd in a Generic record.
    field_ :: HasField_ fd s t a b => Lens s t a b  -- from generic-lens

    -- Update a value through a lens (ASetter is a specialization of Lens).
    over :: ASetter s t a b -> (a -> b) -> s -> t   -- from lens or microlens

For example, here is a record type:

    data R = R { myField :: Int } deriving Generic

The function `over (field_ @"myField") `Opaque`` applies the newtype constructor `Opaque` to the field `"myField"`, but this actually doesn't typecheck as-is. With a bit of help from this module, we can wrap that function as follows:

    onData (over (field_ @"myField") Opaque) . toData
      :: R -> Data _ _   -- type arguments hidden

The result has a type ``Data` _ _`, that from the point of view of GHC.Generics looks just like `R` but with the field `"myField"` wrapped in `Opaque`, as if we had defined:

    data R = R { myField :: Opaque Int } deriving Generic

#### Example usage

We derive an instance of `Show` that hides the `"myField"` field, whatever its type.

    instance Show R where
      showsPrec n = gshowsPrec n
        . onData (over (field_ @"myField") Opaque)
        . toData

    show (R 3) = "R {myField = _}"

# Deriving via

type Surgery s a = Generically (Surgery' s a) Source #

Apply a microsurgery `s` to a type `a` for `DerivingVia`.

For the `Monoid` class, see `ProductSurgery`.

### Example

    {-# LANGUAGE DerivingVia #-}

    -- The constructors must be visible.
    import Generic.Data.Microsurgery
      (Surgery, Surgery'(..), Generically(..), Derecordify)

    data T = T { unT :: Int }
      deriving Show via (Surgery Derecordify T)

    -- T won't be shown as a record:
    --   show (T {unT = 3}) == "T 3"

type ProductSurgery s a = GenericProduct (Surgery' s a) Source #

Apply a microsurgery `s` to a type `a` for `DerivingVia` for the `Monoid` class.

type Surgeries (s :: [Type]) a = Surgery (Cat s) a Source #

Plural of `Surgery`. Apply a list of microsurgeries.

type ProductSurgeries (s :: [Type]) a = ProductSurgery (Cat s) a Source #

Plural of `ProductSurgery`. Apply a list of microsurgeries.

newtype Surgery' s a Source #

See `Surgery`.

Constructors

Surgery' |

Fields

- unSurgery' :: a

#### Instances

Instances details

(Generic a, Coercible (GSurgery s (Rep a)) (Rep a)) => Generic (Surgery' s a) Source # |

Instance details

Defined in Generic.Data.Internal.Microsurgery

Associated Types

type Rep (Surgery' s a) |
Instance details Defined in Generic.Data.Internal.Microsurgery type Rep (Surgery' s a) = GSurgery s (Rep a)

Methods

from :: Surgery' s a -> Rep (Surgery' s a) x Source #

to :: Rep (Surgery' s a) x -> Surgery' s a Source #

type Rep (Surgery' s a) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type Rep (Surgery' s a) = GSurgery s (Rep a)

type family GSurgery s (f :: k -> Type) :: k -> Type Source #

Apply a microsurgery represented by a symbol `s` (declared as a dummy data type) to a generic representation `f`.

#### Instances

Instances details

type GSurgery Derecordify (f :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery Derecordify (f :: k -> Type) = GDerecordify f
type GSurgery Typeage (M1 D ('MetaData nm md pk _nt) f :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery Typeage (M1 D ('MetaData nm md pk _nt) f :: k -> Type) = M1 D ('MetaData nm md pk 'False) f
type GSurgery (CopyRep a) (_1 :: Type -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery (CopyRep a) (_1 :: Type -> Type) = Rep a
type GSurgery (Cat (s ': ss)) (g :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery (Cat (s ': ss)) (g :: k -> Type) = GSurgery s (GSurgery (Cat ss) g)
type GSurgery (Cat ('[] :: [Type])) (g :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery (Cat ('[] :: [Type])) (g :: k -> Type) = g
type GSurgery (OnFields f) (g :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery (OnFields f) (g :: k -> Type) = GOnFields f g
type GSurgery (RenameConstrs rnm) (f :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery (RenameConstrs rnm) (f :: k -> Type) = GRenameConstrs rnm f
type GSurgery (RenameFields rnm) (f :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery (RenameFields rnm) (f :: k -> Type) = GRenameFields rnm f
type GSurgery (OnField s f) (g :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery (OnField s f) (g :: k -> Type) = GOnField s f g

newtype Generically a Source #

A datatype whose instances are defined generically, using the `Generic` representation. `Generically1` is a higher-kinded version of `Generically` that uses `Generic1`.

Generic instances can be derived via ``Generically` A` using `-XDerivingVia`.

    {-# LANGUAGE DeriveGeneric      #-}
    {-# LANGUAGE DerivingStrategies #-}
    {-# LANGUAGE DerivingVia        #-}

    import GHC.Generics (Generic)

    data V4 a = V4 a a a a
      deriving stock Generic

      deriving (Semigroup, Monoid)
      via Generically (V4 a)

This corresponds to `Semigroup` and `Monoid` instances defined by pointwise lifting:

    instance Semigroup a => Semigroup (V4 a) where
      (<>) :: V4 a -> V4 a -> V4 a
      V4 a1 b1 c1 d1 <> V4 a2 b2 c2 d2 =
        V4 (a1 <> a2) (b1 <> b2) (c1 <> c2) (d1 <> d2)

    instance Monoid a => Monoid (V4 a) where
      mempty :: V4 a
      mempty = V4 mempty mempty mempty mempty

Historically this required modifying the type class to include generic method definitions (`-XDefaultSignatures`) and deriving it with the `anyclass` strategy (`-XDeriveAnyClass`). Having a /via type/ like `Generically` decouples the instance from the type class.

Since: base-4.17.0.0

Constructors

Generically a |

#### Instances

Instances details

(Generic a, Monoid (Rep a ())) => Monoid (Generically a) | Since: base-4.17.0.0
Instance details Defined in GHC.Internal.Generics Methods mempty :: Generically a Source # mappend :: Generically a -> Generically a -> Generically a Source # mconcat :: [Generically a] -> Generically a Source #
(Generic a, Semigroup (Rep a ())) => Semigroup (Generically a) | Since: base-4.17.0.0
Instance details Defined in GHC.Internal.Generics Methods (<>) :: Generically a -> Generically a -> Generically a Source # sconcat :: NonEmpty (Generically a) -> Generically a Source # stimes :: Integral b => b -> Generically a -> Generically a Source #
(Generic a, GBounded (Rep a)) => Bounded (Generically a) Source # |
Instance details Defined in Generic.Data.Internal.Generically Methods minBound :: Generically a Source # maxBound :: Generically a Source #
(Generic a, GEnum StandardEnum (Rep a)) => Enum (Generically a) Source # |

Instance details

Defined in Generic.Data.Internal.Generically

Methods

succ :: Generically a -> Generically a Source #

pred :: Generically a -> Generically a Source #

toEnum :: Int -> Generically a Source #

fromEnum :: Generically a -> Int Source #

enumFrom :: Generically a -> [Generically a] Source #

enumFromThen :: Generically a -> Generically a -> [Generically a] Source #

enumFromTo :: Generically a -> Generically a -> [Generically a] Source #

enumFromThenTo :: Generically a -> Generically a -> Generically a -> [Generically a] Source #

Generic a => Generic (Generically a) Source # | This is a hack to implicitly wrap/unwrap in the instances of `Generically`.

Instance details

Defined in Generic.Data.Internal.Generically

Associated Types

type Rep (Generically a) |
Instance details Defined in Generic.Data.Internal.Generically type Rep (Generically a) = Rep a

Methods

from :: Generically a -> Rep (Generically a) x Source #

to :: Rep (Generically a) x -> Generically a Source #

(Generic a, Ord (Rep a ()), GIx (Rep a)) => Ix (Generically a) Source # |

Instance details

Defined in Generic.Data.Internal.Generically

Methods

range :: (Generically a, Generically a) -> [Generically a] Source #

index :: (Generically a, Generically a) -> Generically a -> Int Source #

unsafeIndex :: (Generically a, Generically a) -> Generically a -> Int Source #

inRange :: (Generically a, Generically a) -> Generically a -> Bool Source #

rangeSize :: (Generically a, Generically a) -> Int Source #

unsafeRangeSize :: (Generically a, Generically a) -> Int Source #

(Generic a, GRead0 (Rep a)) => Read (Generically a) Source # |
Instance details Defined in Generic.Data.Internal.Generically Methods readsPrec :: Int -> ReadS (Generically a) Source # readList :: ReadS [Generically a] Source # readPrec :: ReadPrec (Generically a) Source # readListPrec :: ReadPrec [Generically a] Source #
(Generic a, GShow0 (Rep a)) => Show (Generically a) Source # |
Instance details Defined in Generic.Data.Internal.Generically Methods showsPrec :: Int -> Generically a -> ShowS Source # show :: Generically a -> String Source # showList :: [Generically a] -> ShowS Source #
(Generic a, Eq (Rep a ())) => Eq (Generically a) Source # |
Instance details Defined in Generic.Data.Internal.Generically Methods (==) :: Generically a -> Generically a -> Bool Source # (/=) :: Generically a -> Generically a -> Bool Source #
(Generic a, Ord (Rep a ())) => Ord (Generically a) Source # |

Instance details

Defined in Generic.Data.Internal.Generically

Methods

compare :: Generically a -> Generically a -> Ordering Source #

(<) :: Generically a -> Generically a -> Bool Source #

(<=) :: Generically a -> Generically a -> Bool Source #

(>) :: Generically a -> Generically a -> Bool Source #

(>=) :: Generically a -> Generically a -> Bool Source #

max :: Generically a -> Generically a -> Generically a Source #

min :: Generically a -> Generically a -> Generically a Source #

type Rep (Generically a) Source # |
Instance details Defined in Generic.Data.Internal.Generically type Rep (Generically a) = Rep a

newtype GenericProduct a Source #

Product type with generic instances of `Semigroup` and `Monoid`.

This is similar to `Generically` in most cases, but `GenericProduct` also works for types `T` with deriving `via `GenericProduct` U`, where `U` is a generic product type coercible to, but distinct from `T`. In particular, `U` may not have an instance of `Semigroup`, which `Generically` requires.

### Example

Expand

    >>> import Data.Monoid (Sum(..))
    >>> data Point a = Point a a deriving Generic
    >>> :{
      newtype Vector a = Vector (Point a)
        deriving (Semigroup, Monoid)
          via GenericProduct (Point (Sum a))
    :}

If it were `via `Generically` (Point (Sum a))` instead, then `Vector`'s `mappend` (the `Monoid` method) would be defined as `Point`'s `(`<>`)` (the `Semigroup` method), which might not exist, or might not be equivalent to `Vector`'s generic `Semigroup` instance, which would be unlawful.

Constructors

GenericProduct a |

#### Instances

Instances details

(AssertNoSum Semigroup a, Generic a, Monoid (Rep a ())) => Monoid (GenericProduct a) Source # |
Instance details Defined in Generic.Data.Internal.Generically Methods mempty :: GenericProduct a Source # mappend :: GenericProduct a -> GenericProduct a -> GenericProduct a Source # mconcat :: [GenericProduct a] -> GenericProduct a Source #
(AssertNoSum Semigroup a, Generic a, Semigroup (Rep a ())) => Semigroup (GenericProduct a) Source # |
Instance details Defined in Generic.Data.Internal.Generically Methods (<>) :: GenericProduct a -> GenericProduct a -> GenericProduct a Source # sconcat :: NonEmpty (GenericProduct a) -> GenericProduct a Source # stimes :: Integral b => b -> GenericProduct a -> GenericProduct a Source #
Generic a => Generic (GenericProduct a) Source # |

Instance details

Defined in Generic.Data.Internal.Generically

Associated Types

type Rep (GenericProduct a) |
Instance details Defined in Generic.Data.Internal.Generically type Rep (GenericProduct a) = Rep a

Methods

from :: GenericProduct a -> Rep (GenericProduct a) x Source #

to :: Rep (GenericProduct a) x -> GenericProduct a Source #

type Rep (GenericProduct a) Source # |
Instance details Defined in Generic.Data.Internal.Generically type Rep (GenericProduct a) = Rep a

# Synthetic types

data Data (r :: Type -> Type) p Source #

Synthetic data type.

A wrapper to view a generic `Rep` as the datatype it's supposed to represent, without needing a declaration.

#### Instances

Instances details

Generic1 (Data r :: Type -> Type) Source # |

Instance details

Defined in Generic.Data.Internal.Data

Associated Types

type Rep1 (Data r :: Type -> Type) |
Instance details Defined in Generic.Data.Internal.Data type Rep1 (Data r :: Type -> Type) = r

Methods

from1 :: Data r a -> Rep1 (Data r) a Source #

to1 :: Rep1 (Data r) a -> Data r a Source #

Eq1 r => Eq1 (Data r) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods liftEq :: (a -> b -> Bool) -> Data r a -> Data r b -> Bool Source #
Ord1 r => Ord1 (Data r) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods liftCompare :: (a -> b -> Ordering) -> Data r a -> Data r b -> Ordering Source #
GShow1 r => Show1 (Data r) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods liftShowsPrec :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> Data r a -> ShowS Source # liftShowList :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> [Data r a] -> ShowS Source #
Contravariant r => Contravariant (Data r) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods contramap :: (a' -> a) -> Data r a -> Data r a' Source # (>$) :: b -> Data r b -> Data r a Source #
Alternative r => Alternative (Data r) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods empty :: Data r a Source # (<|>) :: Data r a -> Data r a -> Data r a Source # some :: Data r a -> Data r [a] Source # many :: Data r a -> Data r [a] Source #
Applicative r => Applicative (Data r) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods pure :: a -> Data r a Source # (<*>) :: Data r (a -> b) -> Data r a -> Data r b Source # liftA2 :: (a -> b -> c) -> Data r a -> Data r b -> Data r c Source # (*>) :: Data r a -> Data r b -> Data r b Source # (<*) :: Data r a -> Data r b -> Data r a Source #
Functor r => Functor (Data r) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods fmap :: (a -> b) -> Data r a -> Data r b Source # (<$) :: a -> Data r b -> Data r a Source #
Monad r => Monad (Data r) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods (>>=) :: Data r a -> (a -> Data r b) -> Data r b Source # (>>) :: Data r a -> Data r b -> Data r b Source # return :: a -> Data r a Source #
MonadPlus r => MonadPlus (Data r) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods mzero :: Data r a Source # mplus :: Data r a -> Data r a -> Data r a Source #
Foldable r => Foldable (Data r) Source # |

Instance details

Defined in Generic.Data.Internal.Data

Methods

fold :: Monoid m => Data r m -> m Source #

foldMap :: Monoid m => (a -> m) -> Data r a -> m Source #

foldMap' :: Monoid m => (a -> m) -> Data r a -> m Source #

foldr :: (a -> b -> b) -> b -> Data r a -> b Source #

foldr' :: (a -> b -> b) -> b -> Data r a -> b Source #

foldl :: (b -> a -> b) -> b -> Data r a -> b Source #

foldl' :: (b -> a -> b) -> b -> Data r a -> b Source #

foldr1 :: (a -> a -> a) -> Data r a -> a Source #

foldl1 :: (a -> a -> a) -> Data r a -> a Source #

toList :: Data r a -> [a] Source #

null :: Data r a -> Bool Source #

length :: Data r a -> Int Source #

elem :: Eq a => a -> Data r a -> Bool Source #

maximum :: Ord a => Data r a -> a Source #

minimum :: Ord a => Data r a -> a Source #

sum :: Num a => Data r a -> a Source #

product :: Num a => Data r a -> a Source #

Traversable r => Traversable (Data r) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods traverse :: Applicative f => (a -> f b) -> Data r a -> f (Data r b) Source # sequenceA :: Applicative f => Data r (f a) -> f (Data r a) Source # mapM :: Monad m => (a -> m b) -> Data r a -> m (Data r b) Source # sequence :: Monad m => Data r (m a) -> m (Data r a) Source #
Monoid (r p) => Monoid (Data r p) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods mempty :: Data r p Source # mappend :: Data r p -> Data r p -> Data r p Source # mconcat :: [Data r p] -> Data r p Source #
Semigroup (r p) => Semigroup (Data r p) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods (<>) :: Data r p -> Data r p -> Data r p Source # sconcat :: NonEmpty (Data r p) -> Data r p Source # stimes :: Integral b => b -> Data r p -> Data r p Source #
GBounded r => Bounded (Data r p) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods minBound :: Data r p Source # maxBound :: Data r p Source #
GEnum StandardEnum r => Enum (Data r p) Source # |

Instance details

Defined in Generic.Data.Internal.Data

Methods

succ :: Data r p -> Data r p Source #

pred :: Data r p -> Data r p Source #

toEnum :: Int -> Data r p Source #

fromEnum :: Data r p -> Int Source #

enumFrom :: Data r p -> [Data r p] Source #

enumFromThen :: Data r p -> Data r p -> [Data r p] Source #

enumFromTo :: Data r p -> Data r p -> [Data r p] Source #

enumFromThenTo :: Data r p -> Data r p -> Data r p -> [Data r p] Source #

(Functor r, Contravariant r) => Generic (Data r p) Source # |

Instance details

Defined in Generic.Data.Internal.Data

Associated Types

type Rep (Data r p) |
Instance details Defined in Generic.Data.Internal.Data type Rep (Data r p) = r

Methods

from :: Data r p -> Rep (Data r p) x Source #

to :: Rep (Data r p) x -> Data r p Source #

(GShow1 r, Show p) => Show (Data r p) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods showsPrec :: Int -> Data r p -> ShowS Source # show :: Data r p -> String Source # showList :: [Data r p] -> ShowS Source #
Eq (r p) => Eq (Data r p) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods (==) :: Data r p -> Data r p -> Bool Source # (/=) :: Data r p -> Data r p -> Bool Source #
Ord (r p) => Ord (Data r p) Source # |
Instance details Defined in Generic.Data.Internal.Data Methods compare :: Data r p -> Data r p -> Ordering Source # (<) :: Data r p -> Data r p -> Bool Source # (<=) :: Data r p -> Data r p -> Bool Source # (>) :: Data r p -> Data r p -> Bool Source # (>=) :: Data r p -> Data r p -> Bool Source # max :: Data r p -> Data r p -> Data r p Source # min :: Data r p -> Data r p -> Data r p Source #
type Rep1 (Data r :: Type -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Data type Rep1 (Data r :: Type -> Type) = r
type Rep (Data r p) Source # |
Instance details Defined in Generic.Data.Internal.Data type Rep (Data r p) = r

toData :: Generic a => a -> Data (Rep a) p Source #

Conversion between a generic type and the synthetic type made using its representation. Inverse of `fromData`.

fromData :: Generic a => Data (Rep a) p -> a Source #

Inverse of `toData`.

onData :: forall (r :: Type -> Type) (s :: Type -> Type) p x y. (UnifyRep r s, UnifyRep s r) => p (Data r x) (Data s y) -> p (Data r x) (Data s y) Source #

    onData :: _ => (Data r x -> Data s y) -> (Data r x -> Data s y)  -- possible specialization

Can be used with `generic-lens` for type-changing field updates with `field_` (and possibly other generic optics).

A specialization of the identity function to be used to fix types of functions on `Data`, unifying the "spines" of input and output generic representations (the "spine" is everything except field types, which may thus change).

# Microsurgeries

Each microsurgery consists of a type family `F` to modify metadata in GHC Generic representations, and two mappings (that are just `coerce`):

      f :: Data (Rep a) p -> Data (F (Rep a)) p
    unf :: Data (F (Rep a)) p -> Data (Rep a) p

Use `f` with `toData` for generic functions that consume generic values, and `unf` with `fromData` for generic functions that produce generic values. Abstract example:

    genericSerialize . f . toData
    fromData . unf . genericDeserialize

## Renaming of fields and constructors

These surgeries require `DataKinds` and `TypeApplications`.

#### Examples

    {-# LANGUAGE
        DataKinds,
        TypeApplications #-}

    -- Rename all fields to "foo"
    renameFields @(SConst "foo")

    -- Rename constructor "Bar" to "Baz", and leave all others the same
    renameConstrs @(SRename '[ '("Bar", "Baz") ] SId)

data RenameFields rnm Source #

Rename fields using the function `rnm` given as a parameter.

    data Foo = Bar { baz :: Zap }

    -- becomes, renaming "baz" to "bag" --

    data Foo = Bar { bag :: Zap }

This is a defunctionalized symbol, applied using `GSurgery` or `Surgery`.

#### Instances

Instances details

type GSurgery (RenameFields rnm) (f :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery (RenameFields rnm) (f :: k -> Type) = GRenameFields rnm f

renameFields :: forall rnm (f :: Type -> Type) p. Coercible (GSurgery (RenameFields rnm) f) f => Data f p -> Data (GSurgery (RenameFields rnm) f) p Source #

unrenameFields :: forall rnm (f :: Type -> Type) p. Coercible (GSurgery (RenameFields rnm) f) f => Data f p -> Data (GSurgery (RenameFields rnm) f) p Source #

data RenameConstrs rnm Source #

Rename constructors using the function `rnm` given as a parameter.

    data Foo = Bar { baz :: Zap }

    -- becomes, renaming "Bar" to "Car" --

    data Foo = Car { baz :: Zap }

This is a defunctionalized symbol, applied using `GSurgery` or `Surgery`.

#### Instances

Instances details

type GSurgery (RenameConstrs rnm) (f :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery (RenameConstrs rnm) (f :: k -> Type) = GRenameConstrs rnm f

renameConstrs :: forall rnm (f :: Type -> Type) p. Coercible (GSurgery (RenameConstrs rnm) f) f => Data f p -> Data (GSurgery (RenameConstrs rnm) f) p Source #

unrenameConstrs :: forall rnm (f :: Type -> Type) p. Coercible (GSurgery (RenameConstrs rnm) f) f => Data f p -> Data (GSurgery (RenameConstrs rnm) f) p Source #

### Renaming functions

type family f @@ (s :: Symbol) :: Symbol Source #

`f @@ s` is the application of a type-level function symbolized by `f` to a `s :: `Symbol``.

A function `FooToBar` can be defined as follows:

    data FooToBar
    type instance FooToBar @@ "foo" = "bar"

#### Instances

Instances details

type SError @@ s Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type SError @@ s = TypeError ('Text "Invalid name: " ':<>: 'ShowType s) :: Symbol
type SId @@ s Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type SId @@ s = s
type (SConst z) @@ _s Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type (SConst z) @@ _s = z
type (SRename xs f) @@ s Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type (SRename xs f) @@ s = SRename' xs f s

data SId Source #

Identity function ``Symbol` -> `Symbol``.

#### Instances

Instances details

type SId @@ s Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type SId @@ s = s

data SError Source #

Empty function (compile-time error when applied).

#### Instances

Instances details

type SError @@ s Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type SError @@ s = TypeError ('Text "Invalid name: " ':<>: 'ShowType s) :: Symbol

data SConst (s :: Symbol) Source #

Constant function.

#### Instances

Instances details

type (SConst z) @@ _s Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type (SConst z) @@ _s = z

data SRename (xs :: [(Symbol, Symbol)]) f Source #

Define a function for a fixed set of strings, and fall back to `f` for the others.

#### Instances

Instances details

type (SRename xs f) @@ s Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type (SRename xs f) @@ s = SRename' xs f s

## Wrap every field in a type constructor

Give every field a type `f FieldType` (where `f` is a parameter), to obtain a family of types with a shared structure. Some applications of this "higher-kindification" technique may be found in the following blogposts:

- https://www.benjamin.pizza/posts/2017-12-15-functor-functors.html
- https://reasonablypolymorphic.com/blog/higher-kinded-data/

See also the file `test/one-liner-surgery.hs` in this package for an example of using one-liner and generic-lens with a synthetic type constructed with `DOnFields`.

### Example

Derive `Semigroup` and `Monoid` for a product of `Num` types:

    data TwoCounters = MkTwoCounters { c1 :: Int, c2 :: Int }
      deriving Generic
      deriving (Semigroup, Monoid)
        via (ProductSurgery (OnFields Sum) TwoCounters)  -- Surgery here

#### Extensions and imports

Expand

    {-# LANGUAGE DeriveGeneric, DerivingVia #-}
    import Data.Monoid (Sum(..))  -- Constructors must be in scope
    import GHC.Generics (Generic)
    import Generic.Data.Microsurgery
      ( ProductSurgery
      , OnFields
      , GenericProduct(..)  -- Constructors must be in scope
      , Surgery'(..)        --
      )

data OnFields (f :: Type -> Type) Source #

Apply a type constructor `f` to every field type of a generic representation `r`.

    data Color = RGB
      { r :: Int
      , g :: Int
      , b :: Int }

    -- becomes --

    data Color f = RGB
      { r :: f Int
      , g :: f Int
      , b :: f Int }

This is a defunctionalized symbol, applied using `GSurgery` or `Surgery`.

#### Instances

Instances details

type GSurgery (OnFields f) (g :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery (OnFields f) (g :: k -> Type) = GOnFields f g

type DOnFields (f :: Type -> Type) a = Data (GSurgery (OnFields f) (Rep a)) () Source #

Apply a type constructor `f` to every field type of a type `a` to make a synthetic type.

data OnField (s :: Symbol) (f :: Type -> Type) Source #

Apply a type constructor `f` to the field named `s` in a generic record `r`.

    data Vec a = Vec
      { len :: Int
      , contents :: [a] }

    -- with (OnField "len" Sum) becomes --

    data Vec a = Vec
      { len :: Sum Int
      , contents :: [a] }

This is a defunctionalized symbol, applied using `GSurgery` or `Surgery`. See also the synonym `(`%~`)`.

#### Instances

Instances details

type GSurgery (OnField s f) (g :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery (OnField s f) (g :: k -> Type) = GOnField s f g

type (%~) = OnField infixr 4 Source #

Infix name for `OnField`. To be used with `Surgeries` or `Cat`.

### Examples

Expand

Transform one `Int` field into ``Sum` Int` for deriving `Monoid`:

    data Vec a = Vec
      { len :: Int
      , contents :: [a] }
      deriving Generic
      deriving (Eq, Show) via Generically (Vec a)
      deriving (Semigroup, Monoid) via ProductSurgeries '["len" %~ Sum] (Vec a)

Wrap unshowable fields in `Opaque` for deriving `Show`:

    data Unshowable = Unshowable
      { fun :: Int -> Int
      , io :: IO Bool
      , int :: Int }
      deriving Generic
      deriving Show via Surgeries '["fun" %~ Opaque, "io" %~ Opaque] Unshowable

    -- show (Unshowable id (pure True) 42) = "Unshowable _ _ 42"

data Cat (ss :: [Type]) Source #

Compose surgeries together.

#### Instances

Instances details

type GSurgery (Cat (s ': ss)) (g :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery (Cat (s ': ss)) (g :: k -> Type) = GSurgery s (GSurgery (Cat ss) g)
type GSurgery (Cat ('[] :: [Type])) (g :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery (Cat ('[] :: [Type])) (g :: k -> Type) = g

type DCat (ss :: [Type]) a = Data (GSurgery (Cat ss) (Rep a)) () Source #

Make a synthetic type (`Data`) by chaining multiple surgeries.

## Substitute a generic representation from another type

### Example

Derive `Semigroup` and `Monoid` for a product of `Num` types, but using `Sum` for one field and `Product` for the other. In other words, we use the fact that `Polar a` below is isomorphic to the monoid `(`Product` a, `Sum` a)`.

    {-# LANGUAGE DeriveGeneric, DerivingVia #-}
    import Data.Monoid (Sum(..), Product(..))  -- Constructors must be in scope
    import GHC.Generics (Generic)
    import Generic.Data.Microsurgery
      ( ProductSurgery
      , CopyRep
      , GenericProduct(..)  -- Constructors must be in scope
      , Surgery'(..)        --
      )

    data Polar a = Exp { modulus :: a, argument :: a }
      deriving Generic
      deriving (Semigroup, Monoid)
        via (ProductSurgery (CopyRep (Product a, Sum a)) (Polar a))  -- Surgery here

That is the polar representation of a complex number:

    z = modulus * exp(i * argument)

The product of complex numbers defines a monoid isomorphic to the monoid product `(Product Double, Sum Double)` (multiply the moduli, add the arguments).

    z1 <> z2
     = z1 * z2
     = Exp (modulus z1 * modulus z2) (argument z1 + argument z2)

    mempty = 1 = Exp 1 0

data CopyRep a Source #

Change the generic representation to that of another type `a`.

#### Instances

Instances details

type GSurgery (CopyRep a) (_1 :: Type -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery (CopyRep a) (_1 :: Type -> Type) = Rep a

copyRep :: forall a (f :: Type -> Type) p. Coercible (GSurgery (CopyRep a) f) f => Data f p -> Data (GSurgery (CopyRep a) f) p Source #

uncopyRep :: forall a (f :: Type -> Type) p. Coercible f (GSurgery (CopyRep a) f) => Data (GSurgery (CopyRep a) f) p -> Data f p Source #

## Type aging ("denewtypify")

data Typeage Source #

Forget that a type is a `newtype`. (The pun is that "aging" a type makes it no longer "new".)

    newtype Foo = Bar Baz

    -- becomes --

    data Foo = Bar Baz

This is a defunctionalized symbol, applied using `GSurgery` or `Surgery`.

#### Instances

Instances details

type GSurgery Typeage (M1 D ('MetaData nm md pk _nt) f :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery Typeage (M1 D ('MetaData nm md pk _nt) f :: k -> Type) = M1 D ('MetaData nm md pk 'False) f

typeage :: forall (f :: Type -> Type) p. Coercible (GSurgery Typeage f) f => Data f p -> Data (GSurgery Typeage f) p Source #

untypeage :: forall (f :: Type -> Type) p. Coercible f (GSurgery Typeage f) => Data (GSurgery Typeage f) p -> Data f p Source #

## Derecordify

data Derecordify Source #

Forget that a type was declared using record syntax.

    data Foo = Bar { baz :: Zap }

    -- becomes --

    data Foo = Bar Zap

Concretely, set the last field of `MetaCons` to `False` and forget field names.

This is a defunctionalized symbol, applied using `GSurgery` or `Surgery`.

#### Instances

Instances details

type GSurgery Derecordify (f :: k -> Type) Source # |
Instance details Defined in Generic.Data.Internal.Microsurgery type GSurgery Derecordify (f :: k -> Type) = GDerecordify f

derecordify :: forall (f :: Type -> Type) p. Coercible (GSurgery Derecordify f) f => Data f p -> Data (GSurgery Derecordify f) p Source #

underecordify :: forall (f :: Type -> Type) p. Coercible f (GSurgery Derecordify f) => Data (GSurgery Derecordify f) p -> Data f p Source #