    {-# LANGUAGE CPP                    #-}
    {-# LANGUAGE DataKinds              #-}
    {-# LANGUAGE DeriveFunctor          #-}
    {-# LANGUAGE DeriveGeneric          #-}
    {-# LANGUAGE FlexibleContexts       #-}
    {-# LANGUAGE FlexibleInstances      #-}
    {-# LANGUAGE GADTs                  #-}
    {-# LANGUAGE KindSignatures         #-}
    {-# LANGUAGE MagicHash              #-}
    {-# LANGUAGE NoImplicitPrelude      #-}
    {-# LANGUAGE PolyKinds              #-}
    {-# LANGUAGE ScopedTypeVariables    #-}
    {-# LANGUAGE StandaloneDeriving     #-}
    {-# LANGUAGE Trustworthy            #-}
    {-# LANGUAGE TypeFamilies           #-}
    {-# LANGUAGE TypeOperators          #-}
    {-# LANGUAGE TypeSynonymInstances   #-}
    {-# LANGUAGE UndecidableInstances   #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  GHC.Generics
    -- Copyright   :  (c) Universiteit Utrecht 2010-2011, University of Oxford 2012-2014
    -- License     :  see libraries/base/LICENSE
    --
    -- Maintainer  :  libraries@haskell.org
    -- Stability   :  internal
    -- Portability :  non-portable
    --
    -- @since 4.6.0.0
    --
    -- If you're using @GHC.Generics@, you should consider using the
    -- <http://hackage.haskell.org/package/generic-deriving> package, which
    -- contains many useful generic functions.

    module GHC.Generics  (
    -- * Introduction
    --
    -- |
    --
    -- Datatype-generic functions are based on the idea of converting values of
    -- a datatype @T@ into corresponding values of a (nearly) isomorphic type @'Rep' T@.
    -- The type @'Rep' T@ is
    -- built from a limited set of type constructors, all provided by this module. A
    -- datatype-generic function is then an overloaded function with instances
    -- for most of these type constructors, together with a wrapper that performs
    -- the mapping between @T@ and @'Rep' T@. By using this technique, we merely need
    -- a few generic instances in order to implement functionality that works for any
    -- representable type.
    --
    -- Representable types are collected in the 'Generic' class, which defines the
    -- associated type 'Rep' as well as conversion functions 'from' and 'to'.
    -- Typically, you will not define 'Generic' instances by hand, but have the compiler
    -- derive them for you.

    -- ** Representing datatypes
    --
    -- |
    --
    -- The key to defining your own datatype-generic functions is to understand how to
    -- represent datatypes using the given set of type constructors.
    --
    -- Let us look at an example first:
    --
    -- @
    -- data Tree a = Leaf a | Node (Tree a) (Tree a)
    --   deriving 'Generic'
    -- @
    --
    -- The above declaration (which requires the language pragma @DeriveGeneric@)
    -- causes the following representation to be generated:
    --
    -- @
    -- instance 'Generic' (Tree a) where
    --   type 'Rep' (Tree a) =
    --     'D1' ('MetaData \"Tree\" \"Main\" \"package-name\" 'False)
    --       ('C1' ('MetaCons \"Leaf\" 'PrefixI 'False)
    --          ('S1' '(MetaSel 'Nothing
    --                           'NoSourceUnpackedness
    --                           'NoSourceStrictness
    --                           'DecidedLazy)
    --                 ('Rec0' a))
    --        ':+:'
    --        'C1' ('MetaCons \"Node\" 'PrefixI 'False)
    --          ('S1' ('MetaSel 'Nothing
    --                          'NoSourceUnpackedness
    --                          'NoSourceStrictness
    --                          'DecidedLazy)
    --                ('Rec0' (Tree a))
    --           ':*:'
    --           'S1' ('MetaSel 'Nothing
    --                          'NoSourceUnpackedness
    --                          'NoSourceStrictness
    --                          'DecidedLazy)
    --                ('Rec0' (Tree a))))
    --   ...
    -- @
    --
    -- /Hint:/ You can obtain information about the code being generated from GHC by passing
    -- the @-ddump-deriv@ flag. In GHCi, you can expand a type family such as 'Rep' using
    -- the @:kind!@ command.
    --
    -- This is a lot of information! However, most of it is actually merely meta-information
    -- that makes names of datatypes and constructors and more available on the type level.
    --
    -- Here is a reduced representation for 'Tree' with nearly all meta-information removed,
    -- for now keeping only the most essential aspects:
    --
    -- @
    -- instance 'Generic' (Tree a) where
    --   type 'Rep' (Tree a) =
    --     'Rec0' a
    --     ':+:'
    --     ('Rec0' (Tree a) ':*:' 'Rec0' (Tree a))
    -- @
    --
    -- The @Tree@ datatype has two constructors. The representation of individual constructors
    -- is combined using the binary type constructor ':+:'.
    --
    -- The first constructor consists of a single field, which is the parameter @a@. This is
    -- represented as @'Rec0' a@.
    --
    -- The second constructor consists of two fields. Each is a recursive field of type @Tree a@,
    -- represented as @'Rec0' (Tree a)@. Representations of individual fields are combined using
    -- the binary type constructor ':*:'.
    --
    -- Now let us explain the additional tags being used in the complete representation:
    --
    --    * The @'S1' ('MetaSel 'Nothing 'NoSourceUnpackedness 'NoSourceStrictness
    --      'DecidedLazy)@ tag indicates several things. The @'Nothing@ indicates
    --      that there is no record field selector associated with this field of
    --      the constructor (if there were, it would have been marked @'Just
    --      \"recordName\"@ instead). The other types contain meta-information on
    --      the field's strictness:
    --
    --      * There is no @{\-\# UNPACK \#-\}@ or @{\-\# NOUNPACK \#-\}@ annotation
    --        in the source, so it is tagged with @'NoSourceUnpackedness@.
    --
    --      * There is no strictness (@!@) or laziness (@~@) annotation in the
    --        source, so it is tagged with @'NoSourceStrictness@.
    --
    --      * The compiler infers that the field is lazy, so it is tagged with
    --        @'DecidedLazy@. Bear in mind that what the compiler decides may be
    --        quite different from what is written in the source. See
    --        'DecidedStrictness' for a more detailed explanation.
    --
    --      The @'MetaSel@ type is also an instance of the type class 'Selector',
    --      which can be used to obtain information about the field at the value
    --      level.
    --
    --    * The @'C1' ('MetaCons \"Leaf\" 'PrefixI 'False)@ and
    --      @'C1' ('MetaCons \"Node\" 'PrefixI 'False)@ invocations indicate that the enclosed part is
    --      the representation of the first and second constructor of datatype @Tree@, respectively.
    --      Here, the meta-information regarding constructor names, fixity and whether
    --      it has named fields or not is encoded at the type level. The @'MetaCons@
    --      type is also an instance of the type class 'Constructor'. This type class can be used
    --      to obtain information about the constructor at the value level.
    --
    --    * The @'D1' ('MetaData \"Tree\" \"Main\" \"package-name\" 'False)@ tag
    --      indicates that the enclosed part is the representation of the
    --      datatype @Tree@. Again, the meta-information is encoded at the type level.
    --      The @'MetaData@ type is an instance of class 'Datatype', which
    --      can be used to obtain the name of a datatype, the module it has been
    --      defined in, the package it is located under, and whether it has been
    --      defined using @data@ or @newtype@ at the value level.

    -- ** Derived and fundamental representation types
    --
    -- |
    --
    -- There are many datatype-generic functions that do not distinguish between positions that
    -- are parameters or positions that are recursive calls. There are also many datatype-generic
    -- functions that do not care about the names of datatypes and constructors at all. To keep
    -- the number of cases to consider in generic functions in such a situation to a minimum,
    -- it turns out that many of the type constructors introduced above are actually synonyms,
    -- defining them to be variants of a smaller set of constructors.

    -- *** Individual fields of constructors: 'K1'
    --
    -- |
    --
    -- The type constructor 'Rec0' is a variant of 'K1':
    --
    -- @
    -- type 'Rec0' = 'K1' 'R'
    -- @
    --
    -- Here, 'R' is a type-level proxy that does not have any associated values.
    --
    -- There used to be another variant of 'K1' (namely 'Par0'), but it has since
    -- been deprecated.

    -- *** Meta information: 'M1'
    --
    -- |
    --
    -- The type constructors 'S1', 'C1' and 'D1' are all variants of 'M1':
    --
    -- @
    -- type 'S1' = 'M1' 'S'
    -- type 'C1' = 'M1' 'C'
    -- type 'D1' = 'M1' 'D'
    -- @
    --
    -- The types 'S', 'C' and 'D' are once again type-level proxies, just used to create
    -- several variants of 'M1'.

    -- *** Additional generic representation type constructors
    --
    -- |
    --
    -- Next to 'K1', 'M1', ':+:' and ':*:' there are a few more type constructors that occur
    -- in the representations of other datatypes.

    -- **** Empty datatypes: 'V1'
    --
    -- |
    --
    -- For empty datatypes, 'V1' is used as a representation. For example,
    --
    -- @
    -- data Empty deriving 'Generic'
    -- @
    --
    -- yields
    --
    -- @
    -- instance 'Generic' Empty where
    --   type 'Rep' Empty =
    --     'D1' ('MetaData \"Empty\" \"Main\" \"package-name\" 'False) 'V1'
    -- @

    -- **** Constructors without fields: 'U1'
    --
    -- |
    --
    -- If a constructor has no arguments, then 'U1' is used as its representation. For example
    -- the representation of 'Bool' is
    --
    -- @
    -- instance 'Generic' Bool where
    --   type 'Rep' Bool =
    --     'D1' ('MetaData \"Bool\" \"Data.Bool\" \"package-name\" 'False)
    --       ('C1' ('MetaCons \"False\" 'PrefixI 'False) 'U1' ':+:' 'C1' ('MetaCons \"True\" 'PrefixI 'False) 'U1')
    -- @

    -- *** Representation of types with many constructors or many fields
    --
    -- |
    --
    -- As ':+:' and ':*:' are just binary operators, one might ask what happens if the
    -- datatype has more than two constructors, or a constructor with more than two
    -- fields. The answer is simple: the operators are used several times, to combine
    -- all the constructors and fields as needed. However, users /should not rely on
    -- a specific nesting strategy/ for ':+:' and ':*:' being used. The compiler is
    -- free to choose any nesting it prefers. (In practice, the current implementation
    -- tries to produce a more or less balanced nesting, so that the traversal of the
    -- structure of the datatype from the root to a particular component can be performed
    -- in logarithmic rather than linear time.)

    -- ** Defining datatype-generic functions
    --
    -- |
    --
    -- A datatype-generic function comprises two parts:
    --
    --    1. /Generic instances/ for the function, implementing it for most of the representation
    --       type constructors introduced above.
    --
    --    2. A /wrapper/ that for any datatype that is in `Generic`, performs the conversion
    --       between the original value and its `Rep`-based representation and then invokes the
    --       generic instances.
    --
    -- As an example, let us look at a function 'encode' that produces a naive, but lossless
    -- bit encoding of values of various datatypes. So we are aiming to define a function
    --
    -- @
    -- encode :: 'Generic' a => a -> [Bool]
    -- @
    --
    -- where we use 'Bool' as our datatype for bits.
    --
    -- For part 1, we define a class @Encode'@. Perhaps surprisingly, this class is parameterized
    -- over a type constructor @f@ of kind @* -> *@. This is a technicality: all the representation
    -- type constructors operate with kind @* -> *@ as base kind. But the type argument is never
    -- being used. This may be changed at some point in the future. The class has a single method,
    -- and we use the type we want our final function to have, but we replace the occurrences of
    -- the generic type argument @a@ with @f p@ (where the @p@ is any argument; it will not be used).
    --
    -- > class Encode' f where
    -- >   encode' :: f p -> [Bool]
    --
    -- With the goal in mind to make @encode@ work on @Tree@ and other datatypes, we now define
    -- instances for the representation type constructors 'V1', 'U1', ':+:', ':*:', 'K1', and 'M1'.

    -- *** Definition of the generic representation types
    --
    -- |
    --
    -- In order to be able to do this, we need to know the actual definitions of these types:
    --
    -- @
    -- data    'V1'        p                       -- lifted version of Empty
    -- data    'U1'        p = 'U1'                  -- lifted version of ()
    -- data    (':+:') f g p = 'L1' (f p) | 'R1' (g p) -- lifted version of 'Either'
    -- data    (':*:') f g p = (f p) ':*:' (g p)     -- lifted version of (,)
    -- newtype 'K1'    i c p = 'K1' { 'unK1' :: c }    -- a container for a c
    -- newtype 'M1'  i t f p = 'M1' { 'unM1' :: f p }  -- a wrapper
    -- @
    --
    -- So, 'U1' is just the unit type, ':+:' is just a binary choice like 'Either',
    -- ':*:' is a binary pair like the pair constructor @(,)@, and 'K1' is a value
    -- of a specific type @c@, and 'M1' wraps a value of the generic type argument,
    -- which in the lifted world is an @f p@ (where we do not care about @p@).

    -- *** Generic instances
    --
    -- |
    --
    -- The instance for 'V1' is slightly awkward (but also rarely used):
    --
    -- @
    -- instance Encode' 'V1' where
    --   encode' x = undefined
    -- @
    --
    -- There are no values of type @V1 p@ to pass (except undefined), so this is
    -- actually impossible. One can ask why it is useful to define an instance for
    -- 'V1' at all in this case? Well, an empty type can be used as an argument to
    -- a non-empty type, and you might still want to encode the resulting type.
    -- As a somewhat contrived example, consider @[Empty]@, which is not an empty
    -- type, but contains just the empty list. The 'V1' instance ensures that we
    -- can call the generic function on such types.
    --
    -- There is exactly one value of type 'U1', so encoding it requires no
    -- knowledge, and we can use zero bits:
    --
    -- @
    -- instance Encode' 'U1' where
    --   encode' 'U1' = []
    -- @
    --
    -- In the case for ':+:', we produce 'False' or 'True' depending on whether
    -- the constructor of the value provided is located on the left or on the right:
    --
    -- @
    -- instance (Encode' f, Encode' g) => Encode' (f ':+:' g) where
    --   encode' ('L1' x) = False : encode' x
    --   encode' ('R1' x) = True  : encode' x
    -- @
    --
    -- In the case for ':*:', we append the encodings of the two subcomponents:
    --
    -- @
    -- instance (Encode' f, Encode' g) => Encode' (f ':*:' g) where
    --   encode' (x ':*:' y) = encode' x ++ encode' y
    -- @
    --
    -- The case for 'K1' is rather interesting. Here, we call the final function
    -- 'encode' that we yet have to define, recursively. We will use another type
    -- class 'Encode' for that function:
    --
    -- @
    -- instance (Encode c) => Encode' ('K1' i c) where
    --   encode' ('K1' x) = encode x
    -- @
    --
    -- Note how 'Par0' and 'Rec0' both being mapped to 'K1' allows us to define
    -- a uniform instance here.
    --
    -- Similarly, we can define a uniform instance for 'M1', because we completely
    -- disregard all meta-information:
    --
    -- @
    -- instance (Encode' f) => Encode' ('M1' i t f) where
    --   encode' ('M1' x) = encode' x
    -- @
    --
    -- Unlike in 'K1', the instance for 'M1' refers to 'encode'', not 'encode'.

    -- *** The wrapper and generic default
    --
    -- |
    --
    -- We now define class 'Encode' for the actual 'encode' function:
    --
    -- @
    -- class Encode a where
    --   encode :: a -> [Bool]
    --   default encode :: (Generic a, Encode' (Rep a)) => a -> [Bool]
    --   encode x = encode' ('from' x)
    -- @
    --
    -- The incoming 'x' is converted using 'from', then we dispatch to the
    -- generic instances using 'encode''. We use this as a default definition
    -- for 'encode'. We need the 'default encode' signature because ordinary
    -- Haskell default methods must not introduce additional class constraints,
    -- but our generic default does.
    --
    -- Defining a particular instance is now as simple as saying
    --
    -- @
    -- instance (Encode a) => Encode (Tree a)
    -- @
    --
    #if 0
    -- /TODO:/ Add usage example?
    --
    #endif
    -- The generic default is being used. In the future, it will hopefully be
    -- possible to use @deriving Encode@ as well, but GHC does not yet support
    -- that syntax for this situation.
    --
    -- Having 'Encode' as a class has the advantage that we can define
    -- non-generic special cases, which is particularly useful for abstract
    -- datatypes that have no structural representation. For example, given
    -- a suitable integer encoding function 'encodeInt', we can define
    --
    -- @
    -- instance Encode Int where
    --   encode = encodeInt
    -- @

    -- *** Omitting generic instances
    --
    -- |
    --
    -- It is not always required to provide instances for all the generic
    -- representation types, but omitting instances restricts the set of
    -- datatypes the functions will work for:
    --
    --    * If no ':+:' instance is given, the function may still work for
    --      empty datatypes or datatypes that have a single constructor,
    --      but will fail on datatypes with more than one constructor.
    --
    --    * If no ':*:' instance is given, the function may still work for
    --      datatypes where each constructor has just zero or one field,
    --      in particular for enumeration types.
    --
    --    * If no 'K1' instance is given, the function may still work for
    --      enumeration types, where no constructor has any fields.
    --
    --    * If no 'V1' instance is given, the function may still work for
    --      any datatype that is not empty.
    --
    --    * If no 'U1' instance is given, the function may still work for
    --      any datatype where each constructor has at least one field.
    --
    -- An 'M1' instance is always required (but it can just ignore the
    -- meta-information, as is the case for 'encode' above).
    #if 0
    -- *** Using meta-information
    --
    -- |
    --
    -- TODO
    #endif
    -- ** Generic constructor classes
    --
    -- |
    --
    -- Datatype-generic functions as defined above work for a large class
    -- of datatypes, including parameterized datatypes. (We have used 'Tree'
    -- as our example above, which is of kind @* -> *@.) However, the
    -- 'Generic' class ranges over types of kind @*@, and therefore, the
    -- resulting generic functions (such as 'encode') must be parameterized
    -- by a generic type argument of kind @*@.
    --
    -- What if we want to define generic classes that range over type
    -- constructors (such as 'Functor', 'Traversable', or 'Foldable')?

    -- *** The 'Generic1' class
    --
    -- |
    --
    -- Like 'Generic', there is a class 'Generic1' that defines a
    -- representation 'Rep1' and conversion functions 'from1' and 'to1',
    -- only that 'Generic1' ranges over types of kind @* -> *@.
    -- The 'Generic1' class is also derivable.
    --
    -- The representation 'Rep1' is ever so slightly different from 'Rep'.
    -- Let us look at 'Tree' as an example again:
    --
    -- @
    -- data Tree a = Leaf a | Node (Tree a) (Tree a)
    --   deriving 'Generic1'
    -- @
    --
    -- The above declaration causes the following representation to be generated:
    --
    -- @
    -- instance 'Generic1' Tree where
    --   type 'Rep1' Tree =
    --     'D1' ('MetaData \"Tree\" \"Main\" \"package-name\" 'False)
    --       ('C1' ('MetaCons \"Leaf\" 'PrefixI 'False)
    --          ('S1' ('MetaSel 'Nothing
    --                          'NoSourceUnpackedness
    --                          'NoSourceStrictness
    --                          'DecidedLazy)
    --                'Par1')
    --        ':+:'
    --        'C1' ('MetaCons \"Node\" 'PrefixI 'False)
    --          ('S1' ('MetaSel 'Nothing
    --                          'NoSourceUnpackedness
    --                          'NoSourceStrictness
    --                          'DecidedLazy)
    --                ('Rec1' Tree)
    --           ':*:'
    --           'S1' ('MetaSel 'Nothing
    --                          'NoSourceUnpackedness
    --                          'NoSourceStrictness
    --                          'DecidedLazy)
    --                ('Rec1' Tree)))
    --   ...
    --  @
    --
    -- The representation reuses 'D1', 'C1', 'S1' (and thereby 'M1') as well
    -- as ':+:' and ':*:' from 'Rep'. (This reusability is the reason that we
    -- carry around the dummy type argument for kind-@*@-types, but there are
    -- already enough different names involved without duplicating each of
    -- these.)
    --
    -- What's different is that we now use 'Par1' to refer to the parameter
    -- (and that parameter, which used to be @a@), is not mentioned explicitly
    -- by name anywhere; and we use 'Rec1' to refer to a recursive use of @Tree a@.

    -- *** Representation of @* -> *@ types
    --
    -- |
    --
    -- Unlike 'Rec0', the 'Par1' and 'Rec1' type constructors do not
    -- map to 'K1'. They are defined directly, as follows:
    --
    -- @
    -- newtype 'Par1'   p = 'Par1' { 'unPar1' ::   p } -- gives access to parameter p
    -- newtype 'Rec1' f p = 'Rec1' { 'unRec1' :: f p } -- a wrapper
    -- @
    --
    -- In 'Par1', the parameter @p@ is used for the first time, whereas 'Rec1' simply
    -- wraps an application of @f@ to @p@.
    --
    -- Note that 'K1' (in the guise of 'Rec0') can still occur in a 'Rep1' representation,
    -- namely when the datatype has a field that does not mention the parameter.
    --
    -- The declaration
    --
    -- @
    -- data WithInt a = WithInt Int a
    --   deriving 'Generic1'
    -- @
    --
    -- yields
    --
    -- @
    -- class 'Rep1' WithInt where
    --   type 'Rep1' WithInt =
    --     'D1' ('MetaData \"WithInt\" \"Main\" \"package-name\" 'False)
    --       ('C1' ('MetaCons \"WithInt\" 'PrefixI 'False)
    --         ('S1' ('MetaSel 'Nothing
    --                         'NoSourceUnpackedness
    --                         'NoSourceStrictness
    --                         'DecidedLazy)
    --               ('Rec0' Int)
    --          ':*:'
    --          'S1' ('MetaSel 'Nothing
    --                          'NoSourceUnpackedness
    --                          'NoSourceStrictness
    --                          'DecidedLazy)
    --               'Par1'))
    -- @
    --
    -- If the parameter @a@ appears underneath a composition of other type constructors,
    -- then the representation involves composition, too:
    --
    -- @
    -- data Rose a = Fork a [Rose a]
    -- @
    --
    -- yields
    --
    -- @
    -- class 'Rep1' Rose where
    --   type 'Rep1' Rose =
    --     'D1' ('MetaData \"Rose\" \"Main\" \"package-name\" 'False)
    --       ('C1' ('MetaCons \"Fork\" 'PrefixI 'False)
    --         ('S1' ('MetaSel 'Nothing
    --                         'NoSourceUnpackedness
    --                         'NoSourceStrictness
    --                         'DecidedLazy)
    --               'Par1'
    --          ':*:'
    --          'S1' ('MetaSel 'Nothing
    --                          'NoSourceUnpackedness
    --                          'NoSourceStrictness
    --                          'DecidedLazy)
    --               ([] ':.:' 'Rec1' Rose)))
    -- @
    --
    -- where
    --
    -- @
    -- newtype (':.:') f g p = 'Comp1' { 'unComp1' :: f (g p) }
    -- @

    -- *** Representation of unlifted types
    --
    -- |
    --
    -- If one were to attempt to derive a Generic instance for a datatype with an
    -- unlifted argument (for example, 'Int#'), one might expect the occurrence of
    -- the 'Int#' argument to be marked with @'Rec0' 'Int#'@. This won't work,
    -- though, since 'Int#' is of kind @#@ and 'Rec0' expects a type of kind @*@.
    -- In fact, polymorphism over unlifted types is disallowed completely.
    --
    -- One solution would be to represent an occurrence of 'Int#' with 'Rec0 Int'
    -- instead. With this approach, however, the programmer has no way of knowing
    -- whether the 'Int' is actually an 'Int#' in disguise.
    --
    -- Instead of reusing 'Rec0', a separate data family 'URec' is used to mark
    -- occurrences of common unlifted types:
    --
    -- @
    -- data family URec a p
    --
    -- data instance 'URec' ('Ptr' ()) p = 'UAddr'   { 'uAddr#'   :: 'Addr#'   }
    -- data instance 'URec' 'Char'     p = 'UChar'   { 'uChar#'   :: 'Char#'   }
    -- data instance 'URec' 'Double'   p = 'UDouble' { 'uDouble#' :: 'Double#' }
    -- data instance 'URec' 'Int'      p = 'UFloat'  { 'uFloat#'  :: 'Float#'  }
    -- data instance 'URec' 'Float'    p = 'UInt'    { 'uInt#'    :: 'Int#'    }
    -- data instance 'URec' 'Word'     p = 'UWord'   { 'uWord#'   :: 'Word#'   }
    -- @
    --
    -- Several type synonyms are provided for convenience:
    --
    -- @
    -- type 'UAddr'   = 'URec' ('Ptr' ())
    -- type 'UChar'   = 'URec' 'Char'
    -- type 'UDouble' = 'URec' 'Double'
    -- type 'UFloat'  = 'URec' 'Float'
    -- type 'UInt'    = 'URec' 'Int'
    -- type 'UWord'   = 'URec' 'Word'
    -- @
    --
    -- The declaration
    --
    -- @
    -- data IntHash = IntHash Int#
    --   deriving 'Generic'
    -- @
    --
    -- yields
    --
    -- @
    -- instance 'Generic' IntHash where
    --   type 'Rep' IntHash =
    --     'D1' ('MetaData \"IntHash\" \"Main\" \"package-name\" 'False)
    --       ('C1' ('MetaCons \"IntHash\" 'PrefixI 'False)
    --         ('S1' ('MetaSel 'Nothing
    --                         'NoSourceUnpackedness
    --                         'NoSourceStrictness
    --                         'DecidedLazy)
    --               'UInt'))
    -- @
    --
    -- Currently, only the six unlifted types listed above are generated, but this
    -- may be extended to encompass more unlifted types in the future.
    #if 0
    -- *** Limitations
    --
    -- |
    --
    -- /TODO/
    --
    -- /TODO:/ Also clear up confusion about 'Rec0' and 'Rec1' not really indicating recursion.
    --
    #endif
    -----------------------------------------------------------------------------

      -- * Generic representation types
        V1, U1(..), Par1(..), Rec1(..), K1(..), M1(..)
      , (:+:)(..), (:*:)(..), (:.:)(..)

      -- ** Unboxed representation types
      , URec(..)
      , type UAddr, type UChar, type UDouble
      , type UFloat, type UInt, type UWord

      -- ** Synonyms for convenience
      , Rec0, R
      , D1, C1, S1, D, C, S

      -- * Meta-information
      , Datatype(..), Constructor(..), Selector(..)
      , Fixity(..), FixityI(..), Associativity(..), prec
      , SourceUnpackedness(..), SourceStrictness(..), DecidedStrictness(..)
      , Meta(..)

      -- * Generic type classes
      , Generic(..), Generic1(..)

      ) where

    -- We use some base types
    import Data.Either ( Either (..) )
    import Data.Maybe  ( Maybe(..), fromMaybe )
    import GHC.Integer ( Integer, integerToInt )
    import GHC.Prim    ( Addr#, Char#, Double#, Float#, Int#, Word# )
    import GHC.Ptr     ( Ptr )
    import GHC.Types

    -- Needed for instances
    import GHC.Arr     ( Ix )
    import GHC.Base    ( Alternative(..), Applicative(..), Functor(..)
                       , Monad(..), MonadPlus(..), String )
    import GHC.Classes ( Eq(..), Ord(..) )
    import GHC.Enum    ( Bounded, Enum )
    import GHC.Read    ( Read(..), lex, readParen )
    import GHC.Show    ( Show(..), showString )

    -- Needed for metadata
    import Data.Proxy   ( Proxy(..), KProxy(..) )
    import GHC.TypeLits ( Nat, Symbol, KnownSymbol, KnownNat, symbolVal, natVal )

    --------------------------------------------------------------------------------
    -- Representation types
    --------------------------------------------------------------------------------

    -- | Void: used for datatypes without constructors
    data V1 (p :: *)
      deriving (Functor, Generic, Generic1)

    deriving instance Eq   (V1 p)
    deriving instance Ord  (V1 p)
    deriving instance Read (V1 p)
    deriving instance Show (V1 p)

    -- | Unit: used for constructors without arguments
    data U1 (p :: *) = U1
      deriving (Generic, Generic1)

    instance Eq (U1 p) where
      _ == _ = True

    instance Ord (U1 p) where
      compare _ _ = EQ

    instance Read (U1 p) where
      readsPrec d = readParen (d > 10) (\r -> [(U1, s) | ("U1",s) <- lex r ])

    instance Show (U1 p) where
      showsPrec _ _ = showString "U1"

    instance Functor U1 where
      fmap _ _ = U1

    instance Applicative U1 where
      pure _ = U1
      _ <*> _ = U1

    instance Alternative U1 where
      empty = U1
      _ <|> _ = U1

    instance Monad U1 where
      _ >>= _ = U1

    instance MonadPlus U1

    -- | Used for marking occurrences of the parameter
    newtype Par1 p = Par1 { unPar1 :: p }
      deriving (Eq, Ord, Read, Show, Functor, Generic, Generic1)

    instance Applicative Par1 where
      pure a = Par1 a
      Par1 f <*> Par1 x = Par1 (f x)

    instance Monad Par1 where
      Par1 x >>= f = f x

    -- | Recursive calls of kind * -> *
    newtype Rec1 f (p :: *) = Rec1 { unRec1 :: f p }
      deriving (Eq, Ord, Read, Show, Functor, Generic, Generic1)

    instance Applicative f => Applicative (Rec1 f) where
      pure a = Rec1 (pure a)
      Rec1 f <*> Rec1 x = Rec1 (f <*> x)

    instance Alternative f => Alternative (Rec1 f) where
      empty = Rec1 empty
      Rec1 l <|> Rec1 r = Rec1 (l <|> r)

    instance Monad f => Monad (Rec1 f) where
      Rec1 x >>= f = Rec1 (x >>= \a -> unRec1 (f a))

    instance MonadPlus f => MonadPlus (Rec1 f)

    -- | Constants, additional parameters and recursion of kind *
    newtype K1 (i :: *) c (p :: *) = K1 { unK1 :: c }
      deriving (Eq, Ord, Read, Show, Functor, Generic, Generic1)

    instance Applicative f => Applicative (M1 i c f) where
      pure a = M1 (pure a)
      M1 f <*> M1 x = M1 (f <*> x)

    instance Alternative f => Alternative (M1 i c f) where
      empty = M1 empty
      M1 l <|> M1 r = M1 (l <|> r)

    instance Monad f => Monad (M1 i c f) where
      M1 x >>= f = M1 (x >>= \a -> unM1 (f a))

    instance MonadPlus f => MonadPlus (M1 i c f)

    -- | Meta-information (constructor names, etc.)
    newtype M1 (i :: *) (c :: Meta) f (p :: *) = M1 { unM1 :: f p }
      deriving (Eq, Ord, Read, Show, Functor, Generic, Generic1)

    -- | Sums: encode choice between constructors
    infixr 5 :+:
    data (:+:) f g (p :: *) = L1 (f p) | R1 (g p)
      deriving (Eq, Ord, Read, Show, Functor, Generic, Generic1)

    -- | Products: encode multiple arguments to constructors
    infixr 6 :*:
    data (:*:) f g (p :: *) = f p :*: g p
      deriving (Eq, Ord, Read, Show, Functor, Generic, Generic1)

    instance (Applicative f, Applicative g) => Applicative (f :*: g) where
      pure a = pure a :*: pure a
      (f :*: g) <*> (x :*: y) = (f <*> x) :*: (g <*> y)

    instance (Alternative f, Alternative g) => Alternative (f :*: g) where
      empty = empty :*: empty
      (x1 :*: y1) <|> (x2 :*: y2) = (x1 <|> x2) :*: (y1 <|> y2)

    instance (Monad f, Monad g) => Monad (f :*: g) where
      (m :*: n) >>= f = (m >>= \a -> fstP (f a)) :*: (n >>= \a -> sndP (f a))
        where
          fstP (a :*: _) = a
          sndP (_ :*: b) = b

    instance (MonadPlus f, MonadPlus g) => MonadPlus (f :*: g)

    -- | Composition of functors
    infixr 7 :.:
    newtype (:.:) f (g :: * -> *) (p :: *) = Comp1 { unComp1 :: f (g p) }
      deriving (Eq, Ord, Read, Show, Functor, Generic, Generic1)

    instance (Applicative f, Applicative g) => Applicative (f :.: g) where
      pure x = Comp1 (pure (pure x))
      Comp1 f <*> Comp1 x = Comp1 (fmap (<*>) f <*> x)

    instance (Alternative f, Applicative g) => Alternative (f :.: g) where
      empty = Comp1 empty
      Comp1 x <|> Comp1 y = Comp1 (x <|> y)

    -- | Constants of kind @#@
    data family URec (a :: *) (p :: *)

    -- | Used for marking occurrences of 'Addr#'
    data instance URec (Ptr ()) p = UAddr { uAddr# :: Addr# }
      deriving (Eq, Ord, Functor, Generic, Generic1)

    -- | Used for marking occurrences of 'Char#'
    data instance URec Char p = UChar { uChar# :: Char# }
      deriving (Eq, Ord, Show, Functor, Generic, Generic1)

    -- | Used for marking occurrences of 'Double#'
    data instance URec Double p = UDouble { uDouble# :: Double# }
      deriving (Eq, Ord, Show, Functor, Generic, Generic1)

    -- | Used for marking occurrences of 'Float#'
    data instance URec Float p = UFloat { uFloat# :: Float# }
      deriving (Eq, Ord, Show, Functor, Generic, Generic1)

    -- | Used for marking occurrences of 'Int#'
    data instance URec Int p = UInt { uInt# :: Int# }
      deriving (Eq, Ord, Show, Functor, Generic, Generic1)

    -- | Used for marking occurrences of 'Word#'
    data instance URec Word p = UWord { uWord# :: Word# }
      deriving (Eq, Ord, Show, Functor, Generic, Generic1)

    -- | Type synonym for 'URec': 'Addr#'
    type UAddr   = URec (Ptr ())
    -- | Type synonym for 'URec': 'Char#'
    type UChar   = URec Char
    -- | Type synonym for 'URec': 'Double#'
    type UDouble = URec Double
    -- | Type synonym for 'URec': 'Float#'
    type UFloat  = URec Float
    -- | Type synonym for 'URec': 'Int#'
    type UInt    = URec Int
    -- | Type synonym for 'URec': 'Word#'
    type UWord   = URec Word

    -- | Tag for K1: recursion (of kind *)
    data R

    -- | Type synonym for encoding recursion (of kind *)
    type Rec0  = K1 R

    -- | Tag for M1: datatype
    data D
    -- | Tag for M1: constructor
    data C
    -- | Tag for M1: record selector
    data S

    -- | Type synonym for encoding meta-information for datatypes
    type D1 = M1 D

    -- | Type synonym for encoding meta-information for constructors
    type C1 = M1 C

    -- | Type synonym for encoding meta-information for record selectors
    type S1 = M1 S

    -- | Class for datatypes that represent datatypes
    class Datatype d where
      -- | The name of the datatype (unqualified)
      datatypeName :: t d (f :: * -> *) a -> [Char]
      -- | The fully-qualified name of the module where the type is declared
      moduleName   :: t d (f :: * -> *) a -> [Char]
      -- | The package name of the module where the type is declared
      packageName :: t d (f :: * -> *) a -> [Char]
      -- | Marks if the datatype is actually a newtype
      isNewtype    :: t d (f :: * -> *) a -> Bool
      isNewtype _ = False

    instance (KnownSymbol n, KnownSymbol m, KnownSymbol p, SingI nt)
        => Datatype ('MetaData n m p nt) where
      datatypeName _ = symbolVal (Proxy :: Proxy n)
      moduleName   _ = symbolVal (Proxy :: Proxy m)
      packageName  _ = symbolVal (Proxy :: Proxy p)
      isNewtype    _ = fromSing  (sing  :: Sing nt)

    -- | Class for datatypes that represent data constructors
    class Constructor c where
      -- | The name of the constructor
      conName :: t c (f :: * -> *) a -> [Char]

      -- | The fixity of the constructor
      conFixity :: t c (f :: * -> *) a -> Fixity
      conFixity _ = Prefix

      -- | Marks if this constructor is a record
      conIsRecord :: t c (f :: * -> *) a -> Bool
      conIsRecord _ = False

    instance (KnownSymbol n, SingI f, SingI r)
        => Constructor ('MetaCons n f r) where
      conName     _ = symbolVal (Proxy :: Proxy n)
      conFixity   _ = fromSing  (sing  :: Sing f)
      conIsRecord _ = fromSing  (sing  :: Sing r)

    -- | Datatype to represent the fixity of a constructor. An infix
    -- | declaration directly corresponds to an application of 'Infix'.
    data Fixity = Prefix | Infix Associativity Int
      deriving (Eq, Show, Ord, Read, Generic)

    -- | This variant of 'Fixity' appears at the type level.
    data FixityI = PrefixI | InfixI Associativity Nat

    -- | Get the precedence of a fixity value.
    prec :: Fixity -> Int
    prec Prefix      = 10
    prec (Infix _ n) = n

    -- | Datatype to represent the associativity of a constructor
    data Associativity = LeftAssociative
                       | RightAssociative
                       | NotAssociative
      deriving (Eq, Show, Ord, Read, Enum, Bounded, Ix, Generic)

    -- | The unpackedness of a field as the user wrote it in the source code. For
    -- example, in the following data type:
    --
    -- @
    -- data E = ExampleConstructor     Int
    --            {\-\# NOUNPACK \#-\} Int
    --            {\-\#   UNPACK \#-\} Int
    -- @
    --
    -- The fields of @ExampleConstructor@ have 'NoSourceUnpackedness',
    -- 'SourceNoUnpack', and 'SourceUnpack', respectively.
    data SourceUnpackedness = NoSourceUnpackedness
                            | SourceNoUnpack
                            | SourceUnpack
      deriving (Eq, Show, Ord, Read, Enum, Bounded, Ix, Generic)

    -- | The strictness of a field as the user wrote it in the source code. For
    -- example, in the following data type:
    --
    -- @
    -- data E = ExampleConstructor Int ~Int !Int
    -- @
    --
    -- The fields of @ExampleConstructor@ have 'NoSourceStrictness',
    -- 'SourceLazy', and 'SourceStrict', respectively.
    data SourceStrictness = NoSourceStrictness
                          | SourceLazy
                          | SourceStrict
      deriving (Eq, Show, Ord, Read, Enum, Bounded, Ix, Generic)

    -- | The strictness that GHC infers for a field during compilation. Whereas
    -- there are nine different combinations of 'SourceUnpackedness' and
    -- 'SourceStrictness', the strictness that GHC decides will ultimately be one
    -- of lazy, strict, or unpacked. What GHC decides is affected both by what the
    -- user writes in the source code and by GHC flags. As an example, consider
    -- this data type:
    --
    -- @
    -- data E = ExampleConstructor {\-\# UNPACK \#-\} !Int !Int Int
    -- @
    --
    -- * If compiled without optimization or other language extensions, then the
    --   fields of @ExampleConstructor@ will have 'DecidedStrict', 'DecidedStrict',
    --   and 'DecidedLazy', respectively.
    --
    -- * If compiled with @-XStrictData@ enabled, then the fields will have
    --   'DecidedStrict', 'DecidedStrict', and 'DecidedStrict', respectively.
    --
    -- * If compiled with @-O2@ enabled, then the fields will have 'DecidedUnpack',
    --   'DecidedStrict', and 'DecidedLazy', respectively.
    data DecidedStrictness = DecidedLazy
                           | DecidedStrict
                           | DecidedUnpack
      deriving (Eq, Show, Ord, Read, Enum, Bounded, Ix, Generic)

    -- | Class for datatypes that represent records
    class Selector s where
      -- | The name of the selector
      selName :: t s (f :: * -> *) a -> [Char]
      -- | The selector's unpackedness annotation (if any)
      selSourceUnpackedness :: t s (f :: * -> *) a -> SourceUnpackedness
      -- | The selector's strictness annotation (if any)
      selSourceStrictness :: t s (f :: * -> *) a -> SourceStrictness
      -- | The strictness that the compiler inferred for the selector
      selDecidedStrictness :: t s (f :: * -> *) a -> DecidedStrictness

    instance (SingI mn, SingI su, SingI ss, SingI ds)
        => Selector ('MetaSel mn su ss ds) where
      selName _ = fromMaybe "" (fromSing (sing :: Sing mn))
      selSourceUnpackedness _ = fromSing (sing :: Sing su)
      selSourceStrictness   _ = fromSing (sing :: Sing ss)
      selDecidedStrictness  _ = fromSing (sing :: Sing ds)

    -- | Representable types of kind *.
    -- This class is derivable in GHC with the DeriveGeneric flag on.
    class Generic a where
      -- | Generic representation type
      type Rep a :: * -> *
      -- | Convert from the datatype to its representation
      from  :: a -> (Rep a) x
      -- | Convert from the representation to the datatype
      to    :: (Rep a) x -> a

    -- | Representable types of kind * -> *.
    -- This class is derivable in GHC with the DeriveGeneric flag on.
    class Generic1 f where
      -- | Generic representation type
      type Rep1 f :: * -> *
      -- | Convert from the datatype to its representation
      from1  :: f a -> (Rep1 f) a
      -- | Convert from the representation to the datatype
      to1    :: (Rep1 f) a -> f a

    --------------------------------------------------------------------------------
    -- Meta-data
    --------------------------------------------------------------------------------

    -- | Datatype to represent metadata associated with a datatype (@MetaData@),
    -- constructor (@MetaCons@), or field selector (@MetaSel@).
    --
    -- * In @MetaData n m p nt@, @n@ is the datatype's name, @m@ is the module in
    --   which the datatype is defined, @p@ is the package in which the datatype
    --   is defined, and @nt@ is @'True@ if the datatype is a @newtype@.
    --
    -- * In @MetaCons n f s@, @n@ is the constructor's name, @f@ is its fixity,
    --   and @s@ is @'True@ if the constructor contains record selectors.
    --
    -- * In @MetaSel mn su ss ds@, if the field is uses record syntax, then @mn@ is
    --   'Just' the record name. Otherwise, @mn@ is 'Nothing. @su@ and @ss@ are the
    --   field's unpackedness and strictness annotations, and @ds@ is the
    --   strictness that GHC infers for the field.
    data Meta = MetaData Symbol Symbol Symbol Bool
              | MetaCons Symbol FixityI Bool
              | MetaSel  (Maybe Symbol)
                         SourceUnpackedness SourceStrictness DecidedStrictness

    --------------------------------------------------------------------------------
    -- Derived instances
    --------------------------------------------------------------------------------

    deriving instance Generic [a]
    deriving instance Generic (Maybe a)
    deriving instance Generic (Either a b)
    deriving instance Generic Bool
    deriving instance Generic Ordering
    deriving instance Generic (Proxy t)
    deriving instance Generic ()
    deriving instance Generic ((,) a b)
    deriving instance Generic ((,,) a b c)
    deriving instance Generic ((,,,) a b c d)
    deriving instance Generic ((,,,,) a b c d e)
    deriving instance Generic ((,,,,,) a b c d e f)
    deriving instance Generic ((,,,,,,) a b c d e f g)

    deriving instance Generic1 []
    deriving instance Generic1 Maybe
    deriving instance Generic1 (Either a)
    deriving instance Generic1 Proxy
    deriving instance Generic1 ((,) a)
    deriving instance Generic1 ((,,) a b)
    deriving instance Generic1 ((,,,) a b c)
    deriving instance Generic1 ((,,,,) a b c d)
    deriving instance Generic1 ((,,,,,) a b c d e)
    deriving instance Generic1 ((,,,,,,) a b c d e f)

    --------------------------------------------------------------------------------
    -- Copied from the singletons package
    --------------------------------------------------------------------------------

    -- | The singleton kind-indexed data family.
    data family Sing (a :: k)

    -- | A 'SingI' constraint is essentially an implicitly-passed singleton.
    -- If you need to satisfy this constraint with an explicit singleton, please
    -- see 'withSingI'.
    class SingI (a :: k) where
      -- | Produce the singleton explicitly. You will likely need the @ScopedTypeVariables@
      -- extension to use this method the way you want.
      sing :: Sing a

    -- | The 'SingKind' class is essentially a /kind/ class. It classifies all kinds
    -- for which singletons are defined. The class supports converting between a singleton
    -- type and the base (unrefined) type which it is built from.
    class (kparam ~ 'KProxy) => SingKind (kparam :: KProxy k) where
      -- | Get a base type from a proxy for the promoted kind. For example,
      -- @DemoteRep ('KProxy :: KProxy Bool)@ will be the type @Bool@.
      type DemoteRep kparam :: *

      -- | Convert a singleton to its unrefined version.
      fromSing :: Sing (a :: k) -> DemoteRep kparam

    -- Singleton symbols
    data instance Sing (s :: Symbol) where
      SSym :: KnownSymbol s => Sing s

    instance KnownSymbol a => SingI a where sing = SSym

    instance SingKind ('KProxy :: KProxy Symbol) where
      type DemoteRep ('KProxy :: KProxy Symbol) = String
      fromSing (SSym :: Sing s) = symbolVal (Proxy :: Proxy s)

    -- Singleton booleans
    data instance Sing (a :: Bool) where
      STrue  :: Sing 'True
      SFalse :: Sing 'False

    instance SingI 'True  where sing = STrue
    instance SingI 'False where sing = SFalse

    instance SingKind ('KProxy :: KProxy Bool) where
      type DemoteRep ('KProxy :: KProxy Bool) = Bool
      fromSing STrue  = True
      fromSing SFalse = False

    -- Singleton Maybe
    data instance Sing (b :: Maybe a) where
      SNothing :: Sing 'Nothing
      SJust    :: Sing a -> Sing ('Just a)

    instance            SingI 'Nothing  where sing = SNothing
    instance SingI a => SingI ('Just a) where sing = SJust sing

    instance SingKind ('KProxy :: KProxy a) =>
        SingKind ('KProxy :: KProxy (Maybe a)) where
      type DemoteRep ('KProxy :: KProxy (Maybe a)) =
          Maybe (DemoteRep ('KProxy :: KProxy a))
      fromSing SNothing  = Nothing
      fromSing (SJust a) = Just (fromSing a)

    -- Singleton Fixity
    data instance Sing (a :: FixityI) where
      SPrefix :: Sing 'PrefixI
      SInfix  :: Sing a -> Integer -> Sing ('InfixI a n)

    instance SingI 'PrefixI where sing = SPrefix
    instance (SingI a, KnownNat n) => SingI ('InfixI a n) where
      sing = SInfix (sing :: Sing a) (natVal (Proxy :: Proxy n))

    instance SingKind ('KProxy :: KProxy FixityI) where
      type DemoteRep ('KProxy :: KProxy FixityI) = Fixity
      fromSing SPrefix      = Prefix
      fromSing (SInfix a n) = Infix (fromSing a) (I# (integerToInt n))

    -- Singleton Associativity
    data instance Sing (a :: Associativity) where
      SLeftAssociative  :: Sing 'LeftAssociative
      SRightAssociative :: Sing 'RightAssociative
      SNotAssociative   :: Sing 'NotAssociative

    instance SingI 'LeftAssociative  where sing = SLeftAssociative
    instance SingI 'RightAssociative where sing = SRightAssociative
    instance SingI 'NotAssociative   where sing = SNotAssociative

    instance SingKind ('KProxy :: KProxy Associativity) where
      type DemoteRep ('KProxy :: KProxy Associativity) = Associativity
      fromSing SLeftAssociative  = LeftAssociative
      fromSing SRightAssociative = RightAssociative
      fromSing SNotAssociative   = NotAssociative

    -- Singleton SourceUnpackedness
    data instance Sing (a :: SourceUnpackedness) where
      SNoSourceUnpackedness :: Sing 'NoSourceUnpackedness
      SSourceNoUnpack       :: Sing 'SourceNoUnpack
      SSourceUnpack         :: Sing 'SourceUnpack

    instance SingI 'NoSourceUnpackedness where sing = SNoSourceUnpackedness
    instance SingI 'SourceNoUnpack       where sing = SSourceNoUnpack
    instance SingI 'SourceUnpack         where sing = SSourceUnpack

    instance SingKind ('KProxy :: KProxy SourceUnpackedness) where
      type DemoteRep ('KProxy :: KProxy SourceUnpackedness) = SourceUnpackedness
      fromSing SNoSourceUnpackedness = NoSourceUnpackedness
      fromSing SSourceNoUnpack       = SourceNoUnpack
      fromSing SSourceUnpack         = SourceUnpack

    -- Singleton SourceStrictness
    data instance Sing (a :: SourceStrictness) where
      SNoSourceStrictness :: Sing 'NoSourceStrictness
      SSourceLazy         :: Sing 'SourceLazy
      SSourceStrict       :: Sing 'SourceStrict

    instance SingI 'NoSourceStrictness where sing = SNoSourceStrictness
    instance SingI 'SourceLazy         where sing = SSourceLazy
    instance SingI 'SourceStrict       where sing = SSourceStrict

    instance SingKind ('KProxy :: KProxy SourceStrictness) where
      type DemoteRep ('KProxy :: KProxy SourceStrictness) = SourceStrictness
      fromSing SNoSourceStrictness = NoSourceStrictness
      fromSing SSourceLazy         = SourceLazy
      fromSing SSourceStrict       = SourceStrict

    -- Singleton DecidedStrictness
    data instance Sing (a :: DecidedStrictness) where
      SDecidedLazy   :: Sing 'DecidedLazy
      SDecidedStrict :: Sing 'DecidedStrict
      SDecidedUnpack :: Sing 'DecidedUnpack

    instance SingI 'DecidedLazy   where sing = SDecidedLazy
    instance SingI 'DecidedStrict where sing = SDecidedStrict
    instance SingI 'DecidedUnpack where sing = SDecidedUnpack

    instance SingKind ('KProxy :: KProxy DecidedStrictness) where
      type DemoteRep ('KProxy :: KProxy DecidedStrictness) = DecidedStrictness
      fromSing SDecidedLazy   = DecidedLazy
      fromSing SDecidedStrict = DecidedStrict
      fromSing SDecidedUnpack = DecidedUnpack