Safe Haskell  None 

Language  Haskell2010 
Simple operations on generic representations, that only change the typelevel metadata used by certain generic functions.
More complex ones can be found in genericdatasurgery but also, perhaps surprisingly, in genericlens (read more about this just below) and oneliner.
Synopsis
 type Surgery (s :: *) (a :: *) = Generically (Surgery' s a)
 newtype Surgery' (s :: *) (a :: *) = Surgery' {
 unSurgery' :: a
 type family GSurgery (s :: *) (f :: k > *) :: k > *
 newtype Generically a = Generically {
 unGenerically :: a
 data Data r p
 toData :: Generic a => a > Data (Rep a) p
 fromData :: Generic a => Data (Rep a) p > a
 onData :: (UnifyRep r s, UnifyRep s r) => p (Data r x) (Data s y) > p (Data r x) (Data s y)
 data Derecordify :: *
 derecordify :: Coercible (GSurgery Derecordify f) f => Data f p > Data (GSurgery Derecordify f) p
 underecordify :: Coercible f (GSurgery Derecordify f) => Data (GSurgery Derecordify f) p > Data f p
 data Typeage :: *
 typeage :: Coercible (GSurgery Typeage f) f => Data f p > Data (GSurgery Typeage f) p
 untypeage :: Coercible f (GSurgery Typeage f) => Data (GSurgery Typeage f) p > Data f p
 data RenameFields (rnm :: *) :: *
 renameFields :: forall rnm f p. Coercible (GSurgery (RenameFields rnm) f) f => Data f p > Data (GSurgery (RenameFields rnm) f) p
 unrenameFields :: forall rnm f p. Coercible (GSurgery (RenameFields rnm) f) f => Data f p > Data (GSurgery (RenameFields rnm) f) p
 data RenameConstrs (rnm :: *) :: *
 renameConstrs :: forall rnm f p. Coercible (GSurgery (RenameConstrs rnm) f) f => Data f p > Data (GSurgery (RenameConstrs rnm) f) p
 unrenameConstrs :: forall rnm f 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 DOnFields (f :: * > *) (a :: *) = Data (GSurgery (OnFields f) (Rep a)) ()
Surgeries with genericlens
One common and simple situation is to modify the type of some fields, for example wrapping them in a newtype.
We can leverage the genericlens
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 genericlens
 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")
applies the newtype constructor Opaque
Opaque
to the field
"myField"
, but this actually doesn't typecheck asis. 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
, that from the point of view of GHC.Generics
looks just like Data
_ _R
but with the field "myField"
wrapped in
Opaque
, as if we had defined:
data R = R { myField ::Opaque
Int } derivingGeneric
Example usage
We derive an instance of Show
that hides the "myField"
field,
whatever its type.
instanceShow
R whereshowsPrec
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
.
Example
{# LANGUAGE DerivingVia #}  The constructors must be visible. import Generic.Data.Microsurgery (Surgery
,Surgery'
(..),Generically
(..),Derecordify
) data T = T { unT :: Int } derivingShow
via (Surgery
Derecordify
T)  T won't be shown as a record:  show (T {unT = 3}) == "T 3"
newtype Surgery' (s :: *) (a :: *) Source #
See Surgery
.
Surgery'  

type family GSurgery (s :: *) (f :: k > *) :: k > * Source #
Apply a microsurgery represented by a symbol s
(declared as a dummy data
type) to a generic representation f
.
Instances
type GSurgery Derecordify (f :: k > Type) Source #  
Defined in Generic.Data.Internal.Microsurgery  
type GSurgery Typeage (M1 D (MetaData nm md pk _nt) f :: k > Type) Source #  
type GSurgery (RenameFields rnm) (f :: k > Type) Source #  
Defined in Generic.Data.Internal.Microsurgery  
type GSurgery (RenameConstrs rnm) (f :: k > Type) Source #  
Defined in Generic.Data.Internal.Microsurgery  
type GSurgery (OnFields f) (g :: k > Type) Source #  
Defined in Generic.Data.Internal.Microsurgery 
newtype Generically a Source #
Type with instances derived via Generic
.
Generically  

Instances
Synthetic types
Synthetic data type.
A wrapper to view a generic Rep
as the datatype it's supposed to
represent, without needing a declaration.
Instances
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
.
onData :: (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 genericlens
for typechanging 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
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
type GSurgery Derecordify (f :: k > Type) Source #  
Defined in Generic.Data.Internal.Microsurgery 
derecordify :: Coercible (GSurgery Derecordify f) f => Data f p > Data (GSurgery Derecordify f) p Source #
underecordify :: Coercible f (GSurgery Derecordify f) => Data (GSurgery Derecordify f) p > Data f p Source #
Type aging ("denewtypify")
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 samerenameConstrs
@(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
type GSurgery (RenameFields rnm) (f :: k > Type) Source #  
Defined in Generic.Data.Internal.Microsurgery 
renameFields :: forall rnm f p. Coercible (GSurgery (RenameFields rnm) f) f => Data f p > Data (GSurgery (RenameFields rnm) f) p Source #
unrenameFields :: forall rnm f 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
type GSurgery (RenameConstrs rnm) (f :: k > Type) Source #  
Defined in Generic.Data.Internal.Microsurgery 
renameConstrs :: forall rnm f p. Coercible (GSurgery (RenameConstrs rnm) f) f => Data f p > Data (GSurgery (RenameConstrs rnm) f) p Source #
unrenameConstrs :: forall rnm f 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 typelevel function symbolized by f
to a s ::
.Symbol
A function FooToBar
can be defined as follows:
data FooToBar
type instance FooToBar @@
"foo" = "bar"
Empty function (compiletime error when applied).
data SRename (xs :: [(Symbol, Symbol)]) (f :: *) Source #
Define a function for a fixed set of strings, and fall back to f
for the others.
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. This
"higherkindification" technique is presented in the following
blogposts:
 https://www.benjamin.pizza/posts/20171215functorfunctors.html
 https://reasonablypolymorphic.com/blog/higherkindeddata/
See also the file test/onelinersurgery.hs
in this package for an
example of using oneliner and genericlens with a synthetic type
constructed with DOnFields
.