generic-data
Deriving instances with GHC.Generics and related utilities
https://github.com/Lysxia/generic-data#readme
LTS Haskell 22.33: | 1.1.0.0@rev:2 |
Stackage Nightly 2024-09-07: | 1.1.0.0@rev:2 |
Latest on Hackage: | 1.1.0.0@rev:2 |
generic-data-1.1.0.0@sha256:dec514cd4fcdf31afb28b16476293ca1737b1c489a0872220aaffa2ae152f8a0,4245
Module documentation for 1.1.0.0
- Generic
- Generic.Data
- Generic.Data.Internal
- Generic.Data.Internal.Compat
- Generic.Data.Internal.Data
- Generic.Data.Internal.Enum
- Generic.Data.Internal.Error
- Generic.Data.Internal.Functions
- Generic.Data.Internal.Generically
- Generic.Data.Internal.Meta
- Generic.Data.Internal.Microsurgery
- Generic.Data.Internal.Newtype
- Generic.Data.Internal.Prelude
- Generic.Data.Internal.Read
- Generic.Data.Internal.Resolvers
- Generic.Data.Internal.Show
- Generic.Data.Internal.Traversable
- Generic.Data.Internal.Utils
- Generic.Data.Microsurgery
- Generic.Data.Orphans
- Generic.Data.Types
- Generic.Data.Internal
- Generic.Data
Generic data types in Haskell
![GitHub CI](https://github.com/Lysxia/generic-data/workflows/CI/badge.svg)
Utilities for GHC.Generics
.
Generic deriving for standard classes
Example: generically deriving Semigroup instances for products
Semi-automatic method using gmappend
data Foo a = Bar [a] [a] deriving Generic
instance Semigroup (Foo a) where
(<>) = gmappend
This library also synergizes with the DerivingVia
extension
(introduced in GHC 8.6), thanks to the Generically
newtype.
data Foo a = Bar [a] [a]
deriving Generic
deriving Semigroup via (Generically (Foo a))
These examples can be found in test/example.hs
.
Note for completeness, the first example uses the following extensions and imports:
{-# LANGUAGE DeriveGeneric #-}
-- base
import Data.Semigroup (Semigroup(..))
-- generic-data
import Generic.Data (Generic, gmappend)
import Generic.Data.Orphans ()
The second example makes these additions on top:
{-# LANGUAGE
DerivingStrategies,
DerivingVia #-} -- since GHC 8.6.1
-- In addition to the previous imports
import Generic.Data (Generically(..))
Supported classes
Supported classes that GHC currently can’t derive: Semigroup
, Monoid
,
Applicative
, Alternative
, Eq1
, Ord1
, Show1
.
Other classes from base are also supported, even though GHC can already derive them:
Eq
,Ord
,Enum
,Bounded
,Show
,Read
(derivable by the standard);Functor
,Foldable
,Traversable
(derivable via extensions,DeriveFunctor
, etc.).
To derive type classes outside of the standard library, it might be worth taking a look at one-liner.
Type metadata
Extract type names, constructor names, number and arities of constructors, etc..
Type surgery
generic-data offers simple operations (microsurgeries) on generic representations.
More surgeries can be found in generic-data-surgery, and suprisingly, in generic-lens and one-liner.
For more details, see also:
-
the module
Generic.Data.Microsurgery
; -
the files
test/lens-surgery.hs
andone-liner-surgery.hs
.
Surgery example
Derive an instance of Show
generically for a record type,
but as if it were not a record.
{-# LANGUAGE DeriveGeneric #-}
import Generic.Data (Generic, gshowsPrec)
import Generic.Data.Microsurgery (toData, derecordify)
-- An example record type
newtype T = T { unT :: Int } deriving Generic
-- Naively deriving Show would result in this being shown:
--
-- show (T 3) = "T {unT = 3}"
--
-- But instead, with a simple surgery, unrecordify, we can forget T was
-- declared as a record:
--
-- show (T 3) = "T 3"
instance Show T where
showsPrec n = gshowsPrec n . derecordify . toData
-- This example can be found in test/microsurgery.hs
Alternatively, using DerivingVia
:
{-# LANGUAGE DeriveGeneric, DerivingVia #-}
import Generic.Data (Generic) -- Reexported from GHC.Generics
-- Constructors must be visible to use DerivingVia
import Generic.Data.Microsurgery (Surgery, Surgery'(..), Generically(..), Derecordify)
data V = V { v1 :: Int, v2 :: Int }
deriving Generic
deriving Show via (Surgery Derecordify V)
-- show (V {v1 = 3, v2 = 4}) = "V 3 4"
Related links
generic-data aims to subsume generic deriving features of the following packages:
- semigroups: generic
Semigroup
,Monoid
, but with a heavier dependency footprint. - transformers-compat:
generic
Eq1
,Ord1
,Show1
. - generic-deriving:
doesn’t derive the classes in base (defines clones of these classes as a toy
example); has Template Haskell code to derive
Generic
(not in generic-data).
Other relevant links.
- deriving-compat: deriving with Template Haskell.
- one-liner: another approach
to using
GHC.Generics
to derive instances of many type classes, including but not restricted to the above classes (this is done in one-liner-instances). - singletons, first-class-families (second one written by me) libraries for dependently-typed programming in Haskell.
- coercible-utils: utilities for coercible types.
Internal module policy
Modules under Generic.Data.Internal
are not subject to any versioning policy.
Breaking changes may apply to them at any time.
If something in those modules seems useful, please report it or create a pull request to export it from an external module.
All contributions are welcome. Open an issue or a pull request on Github!
Changes
1.1.0.0
- Remove
Eq
andOrd
forGenerically1
instances. They are now available in base 4.18, and base-orphans 0.8.8 for backwards compatibility.
1.0.0.1
- Compatibility with base 4.18 (GHC 9.6)
1.0.0.0
-
Generically
andGenerically1
are in base 4.17 (GHC 9.4.1)!- generic-data reexports
Generically
andGenerically1
if using base >= 4.17. The following instances remain as orphans:Eq
,Ord
,Read
,Show
,Enum
,Ix
,Bounded
,Foldable
,Traversable
,Read1
,Show1
. - base 4.17 includes instances for the non-stock-derivable classes:
Semigroup
andMonoid
forGenerically
;Eq1
,Ord1
,Functor
,Applicative
, andAlternative
forGenerically1
. - Note: the
Semigroup
andMonoid
instances of base’sGenerically
are those of generic-data’sGenericProduct
(which is subtly different fromGenerically
’s previous instance in generic-data). Generically
andGenerically1
are no longer defined using record syntax, so theunGenerically
(1
) field accessor no longer exists. The field accessors forFiniteEnumeration
andGenericProduct
were also removed for uniformity.
- generic-data reexports
0.9.2.1
- No external changes.
- Use cabal-docspec instead of doctest
0.9.2.0
- Add instance of
Bounded
forFiniteEnumeration
(the same asGenerically
)
0.9.1.0
- Fix
conIdToString
(it was completely broken) - Add
conIdMin
andconIdMax
representing the leftmost and rightmost constructors of a data type. - Add
NonEmptyType
andIsEmptyType
to express the constraint that a generic type must or must not be empty. - Reexport
Generic
andGeneric1
for convenience.
0.9.0.0
-
Improved definition of
gfoldMap
,gtraverse
, andsequenceA
. The optimized Core ofTraversable
instances eliminates allGHC.Generic
instance boilerplate. In many cases, it is identical to the result of GHC’sDeriveFoldable
andDeriveTraversable
extensions (note: this was already not a problem forgfmap
).It’s worth noting that there are currently issues with inlining which prevent optimizations that generic-data would ideally rely on.
-
The biggest issue is that GHC will not even inline the
to
andfrom
methods of theGeneric
instance it derives for large types (this shows up at around 5 constructors and 10 fields, which is indeed not really big). This will be fixed by a patch for GHC (WIP): https://gitlab.haskell.org/ghc/ghc/-/merge_requests/2965 -
There appear to be some more inlining issues beyond that (issue #40).
-
0.8.3.0
- Add generic
Read
. Thanks to RyanGlScott.
0.8.2.0
- Add microsurgery
CopyRep
. - Improve documentation of
Microsurgery
module. - Fix a bug where
gshowsPrec
would incorrectly display prefix uses of symbol data constructors or record selectors (e.g.,data R = (:!:) Int Int
ordata S = MkS { (##) :: Int -> Int }
). Thanks to RyanGlScott. - Fix a bug where
gshowsPrec
would incorrectly display infix uses of alphanumeric data constructors (e.g.,data T = Int `MkT` Int
). Thanks to RyanGlScott.
0.8.1.0
- Add
Old
type family mapping newtypes to their underlying type.
0.8.0.0
-
Add
GenericProduct
, for derivingvia GenericProduct B
whenB
is not the typeA
you want the derived instance for. Note this used to beGenerically
’s behavior forMonoid
before 0.7.0.0. -
Add generic implementations for
Ix
. Thanks to Topsii. -
Add
conIdNamed
, to get aConId
by its type-level name -
Add instance
Show (ConId a)
-
Improve type errors for deriving
Semigroup
andMonoid
viaGenerically
. Thanks to yairchu.
0.7.0.0
- Change
Monoid
instance forGenerically
, to be compatible with users’ non-generic instances ofSemigroup
. Thanks to yairchu. - Add
gcoerce
,gcoerceBinop
.
0.6.0.1
- Fix derivation of
Show1
for(:.:)
0.6.0.0
- Add
Surgery
newtype for DerivingVia Derecordify
,Typeage
,RenameFields
,RenameConstrs
,OnFields
are no longer type families, but defunctionalized symbols to be applied usingGSurgery
.
0.5.0.0
- Specialize
onData
toData
- Add some instances for
U1
andV1
inMicrosurgery
- Add
OnFields
andDOnFields
surgeries (“higher-kindification”)
0.4.0.0
-
Created
Microsurgery
module. Initial set of surgeries:Derecordify
Typeage
RenameFields
,RenameConstrs
- Some doc about using generic-lens for surgeries
0.3.0.0
- Add generic implementations of
enumFrom
,enumFromThen
,enumFromTo
,enumFromThenTo
. They are actually required to be explicit for correctEnum
instances. Thanks to Topsii. - Parameterize
GEnum
by a type-level option, and addFiniteEnum
option to allowEnum
to be derived for composite types. Thanks to Topsii.
0.2.0.0
- Remove
Generic.Data.Types.Map
- Add
Generic.Data.Data.Types.toData
andfromData
- Remove
Defun
module (subsumed byfirst-class-families
package)
0.1.1.0
- Add
gconIndex
- Interface for constructor tags
- Type-level
Meta
accessors - Add basic
Newtype
functions
0.1.0.0
Released generic-data