Generic data types in Haskell

Utilities for GHC.Generics
.
Generic deriving for standard classes
{-# LANGUAGE DeriveGeneric #-}
-- base
import Data.Semigroup (Semigroup(..))
import GHC.Generics
-- generic-data
import Generic.Data (gmappend, Generically(..))
import Generic.Data.Orphans ()
data Foo a = Bar [a] [a] deriving Generic
instance Semigroup (Foo a) where
(<>) = gmappend
-- also with some additional extensions --
{-# LANGUAGE
DerivingStrategies,
DerivingVia #-} -- since GHC 8.6.1
data Foo a = Bar [a] [a]
deriving Generic
deriving Semigroup via (Generically (Foo a))
-- This example can be found in test/example.hs
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
(standard);
Functor
, Foldable
, Traversable
(via extensions, DeriveFunctor
, etc.).
(Read
is currently not implemented.)
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 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:
Surgery example
Derive an instance of Show
generically for a record type,
but as if it were not a record.
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generic (Generic)
import Generic.Data (gshowsPrec)
import Generic.Data.Microsurgery (toData, derecordify)
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
Related links
generic-data aims to subsume generic deriving features of the following
packages:
- semigroups: generic
Semigroup
, Monoid
, but with a heavy 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
.
Here are other relevant links.
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!