generic-data-0.4.0.0: Utilities for GHC.Generics

Safe HaskellNone
LanguageHaskell2010

Generic.Data.Microsurgery

Contents

Description

Simple operations on generic representations, that only change the type-level metadata used by certain generic functions.

More complex ones can be found in generic-data-surgery and, surprisingly, in generic-lens (read more about this just below).

Synopsis

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 = _}"

Synthetic types

data Data r 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
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 #

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

return :: a -> Data r a #

fail :: String -> Data r a #

Functor r => Functor (Data r) Source # 
Instance details

Defined in Generic.Data.Internal.Data

Methods

fmap :: (a -> b) -> Data r a -> Data r b #

(<$) :: a -> Data r b -> Data r a #

Applicative r => Applicative (Data r) Source # 
Instance details

Defined in Generic.Data.Internal.Data

Methods

pure :: a -> Data r a #

(<*>) :: Data r (a -> b) -> Data r a -> Data r b #

liftA2 :: (a -> b -> c) -> Data r a -> Data r b -> Data r c #

(*>) :: Data r a -> Data r b -> Data r b #

(<*) :: Data r a -> Data r b -> Data r a #

Foldable r => Foldable (Data r) Source # 
Instance details

Defined in Generic.Data.Internal.Data

Methods

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

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

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

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

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

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

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

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

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

null :: Data r a -> Bool #

length :: Data r a -> Int #

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

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

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

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

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

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) #

sequenceA :: Applicative f => Data r (f a) -> f (Data r a) #

mapM :: Monad m => (a -> m b) -> Data r a -> m (Data r b) #

sequence :: Monad m => Data r (m a) -> m (Data r a) #

Contravariant r => Contravariant (Data r) Source # 
Instance details

Defined in Generic.Data.Internal.Data

Methods

contramap :: (a -> b) -> Data r b -> Data r a #

(>$) :: b -> Data r b -> Data r a #

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 #

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 #

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 #

liftShowList :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> [Data r a] -> ShowS #

Alternative r => Alternative (Data r) Source # 
Instance details

Defined in Generic.Data.Internal.Data

Methods

empty :: Data r a #

(<|>) :: Data r a -> Data r a -> Data r a #

some :: Data r a -> Data r [a] #

many :: Data r a -> Data r [a] #

MonadPlus r => MonadPlus (Data r) Source # 
Instance details

Defined in Generic.Data.Internal.Data

Methods

mzero :: Data r a #

mplus :: Data r a -> Data r a -> Data r a #

Generic1 (Data r :: Type -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Data

Associated Types

type Rep1 (Data r) :: k -> Type #

Methods

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

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

GBounded r => Bounded (Data r p) Source # 
Instance details

Defined in Generic.Data.Internal.Data

Methods

minBound :: Data r p #

maxBound :: Data r p #

GEnum StandardEnum r => Enum (Data r p) Source # 
Instance details

Defined in Generic.Data.Internal.Data

Methods

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

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

toEnum :: Int -> Data r p #

fromEnum :: Data r p -> Int #

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

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

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

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

Eq (r p) => Eq (Data r p) Source # 
Instance details

Defined in Generic.Data.Internal.Data

Methods

(==) :: Data r p -> Data r p -> Bool #

(/=) :: Data r p -> Data r p -> Bool #

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 #

(<) :: Data r p -> Data r p -> Bool #

(<=) :: Data r p -> Data r p -> Bool #

(>) :: Data r p -> Data r p -> Bool #

(>=) :: Data r p -> Data r p -> Bool #

max :: Data r p -> Data r p -> Data r p #

min :: Data r p -> Data r p -> Data r p #

(GShow1 r, Show p) => Show (Data r p) Source # 
Instance details

Defined in Generic.Data.Internal.Data

Methods

showsPrec :: Int -> Data r p -> ShowS #

show :: Data r p -> String #

showList :: [Data r p] -> ShowS #

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

Defined in Generic.Data.Internal.Data

Associated Types

type Rep (Data r p) :: Type -> Type #

Methods

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

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

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 #

sconcat :: NonEmpty (Data r p) -> Data r p #

stimes :: Integral b => b -> Data r p -> Data r p #

Monoid (r p) => Monoid (Data r p) Source # 
Instance details

Defined in Generic.Data.Internal.Data

Methods

mempty :: Data r p #

mappend :: Data r p -> Data r p -> Data r p #

mconcat :: [Data r p] -> Data r p #

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.

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

Inverse of fromData.

onData :: (UnifyRep (Rep a) (Rep b), UnifyRep (Rep a) (Rep b)) => p a b -> p a b Source #

onData :: _ => (a -> b) -> (a -> b)  -- 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 using Data as input or output, 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

Derecordify

type family Derecordify (f :: k -> *) :: k -> * 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.

Instances
type Derecordify (U1 :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type Derecordify (U1 :: k -> Type) = (U1 :: k -> Type)
type Derecordify (V1 :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type Derecordify (V1 :: k -> Type) = (V1 :: k -> Type)
type Derecordify (f :*: g :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type Derecordify (f :*: g :: k -> Type) = Derecordify f :*: Derecordify g
type Derecordify (f :+: g :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type Derecordify (f :+: g :: k -> Type) = Derecordify f :+: Derecordify g
type Derecordify (M1 S (MetaSel _nm su ss ds) f :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type Derecordify (M1 S (MetaSel _nm su ss ds) f :: k -> Type) = M1 S (MetaSel (Nothing :: Maybe Symbol) su ss ds) f
type Derecordify (M1 C (MetaCons nm fx _isRecord) f :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type Derecordify (M1 C (MetaCons nm fx _isRecord) f :: k -> Type) = M1 C (MetaCons nm fx False) (Derecordify f)
type Derecordify (M1 D m f :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type Derecordify (M1 D m f :: k -> Type) = M1 D m (Derecordify f)

Type aging ("denewtypify")

type family Typeage (f :: k -> *) :: k -> * Source #

Forget that a type is a newtype.

newtype Foo = Bar Baz

-- becomes --

data Foo = Bar Baz
Instances
type Typeage (M1 D (MetaData nm md pk _nt) f :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type Typeage (M1 D (MetaData nm md pk _nt) f :: k -> Type) = M1 D (MetaData nm md pk False) f

typeage :: Coercible (Typeage f) f => Data f p -> Data (Typeage f) p Source #

untypeage :: Coercible f (Typeage f) => Data (Typeage f) p -> Data f p Source #

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)

type family RenameFields (rnm :: *) (f :: k -> *) :: k -> * 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 }
Instances
type RenameFields rnm (f :*: g :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type RenameFields rnm (f :*: g :: k -> Type) = RenameFields rnm f :*: RenameFields rnm g
type RenameFields rnm (f :+: g :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type RenameFields rnm (f :+: g :: k -> Type) = RenameFields rnm f :+: RenameFields rnm g
type RenameFields rnm (M1 C m f :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type RenameFields rnm (M1 C m f :: k -> Type) = M1 C m (RenameFields rnm f)
type RenameFields rnm (M1 D m f :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type RenameFields rnm (M1 D m f :: k -> Type) = M1 D m (RenameFields rnm f)
type RenameFields rnm (M1 S (MetaSel (Just nm) su ss ds) f :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type RenameFields rnm (M1 S (MetaSel (Just nm) su ss ds) f :: k -> Type) = M1 S (MetaSel (Just (rnm @@ nm)) su ss ds) f

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

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

type family RenameConstrs (rnm :: *) (f :: k -> *) :: k -> * 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 }
Instances
type RenameConstrs rnm (f :*: g :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type RenameConstrs rnm (f :*: g :: k -> Type) = RenameConstrs rnm f :*: RenameConstrs rnm g
type RenameConstrs rnm (f :+: g :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type RenameConstrs rnm (f :+: g :: k -> Type) = RenameConstrs rnm f :+: RenameConstrs rnm g
type RenameConstrs rnm (M1 D m f :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type RenameConstrs rnm (M1 D m f :: k -> Type) = M1 D m (RenameConstrs rnm f)
type RenameConstrs rnm (M1 C (MetaCons nm fi ir) f :: k -> Type) Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type RenameConstrs rnm (M1 C (MetaCons nm fi ir) f :: k -> Type) = M1 C (MetaCons (rnm @@ nm) fi ir) f

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

unrenameConstrs :: forall rnm f p. Coercible (RenameConstrs rnm f) f => Data f p -> Data (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
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
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
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
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
type (SRename xs f) @@ s Source # 
Instance details

Defined in Generic.Data.Internal.Microsurgery

type (SRename xs f) @@ s = SRename' xs f s