kind-generics-0.1.0.0: src/Generics/Kind.hs
{-# language DataKinds #-}
{-# language KindSignatures #-}
{-# language PolyKinds #-}
{-# language TypeFamilies #-}
{-# language GADTs #-}
{-# language ConstraintKinds #-}
{-# language TypeOperators #-}
{-# language StandaloneDeriving #-}
{-# language FlexibleContexts #-}
{-# language UndecidableInstances #-}
{-# language MultiParamTypeClasses #-}
{-# language FlexibleInstances #-}
{-# language ExistentialQuantification #-}
{-# language DefaultSignatures #-}
{-# language ScopedTypeVariables #-}
{-# language TypeApplications #-}
{-# language AllowAmbiguousTypes #-}
{-# language QuantifiedConstraints #-}
-- | Main module of @kind-generics@. Please refer to the @README@ file for documentation on how to use this package.
module Generics.Kind (
module Data.PolyKinded
, module Data.PolyKinded.Atom
-- * Generic representation types
, (:+:)(..), (:*:)(..), U1(..), M1(..)
, F(..), (:=>:)(..), E(..)
-- * Generic type classes
, GenericK(..)
, GenericF, fromF, toF
, GenericN, fromN, toN
, GenericS, fromS, toS
-- * Bridging with "GHC.Generics"
, Conv(..)
) where
import Data.PolyKinded
import Data.PolyKinded.Atom
import Data.Kind
import GHC.Generics.Extra hiding ((:=>:))
import qualified GHC.Generics.Extra as GG
-- | Fields: used to represent each of the (visible) arguments to a constructor.
-- Replaces the 'K1' type from "GHC.Generics". The type of the field is
-- represented by an 'Atom' from "Data.PolyKinded.Atom".
--
-- > instance GenericK [] (a :&&: LoT0) where
-- > type RepK [] = F V0 :*: F ([] :$: V0)
newtype F (t :: Atom d (*)) (x :: LoT d) = F { unF :: Ty t x }
deriving instance Show (Ty t x) => Show (F t x)
-- | Constraints: used to represent constraints in a constructor.
-- Replaces the '(:=>:)' type from "GHC.Generics.Extra".
--
-- > data Showable a = Show a => a -> X a
-- >
-- > instance GenericK Showable (a :&&: LoT0) where
-- > type RepK Showable = (Show :$: a) :=>: (F V0)
data (:=>:) (c :: Atom d Constraint) (f :: LoT d -> *) (x :: LoT d) where
C :: Ty c x => f x -> (c :=>: f) x
-- | Existentials: a representation of the form @E f@ describes
-- a constructor whose inner type is represented by @f@, and where
-- the type variable at index 0, @V0@, is existentially quantified.
--
-- > data Exists where
-- > E :: t -> Exists
-- >
-- > instance GenericK Exists LoT0 where
-- > type RepK Exists = E (F V0)
data E (f :: LoT (k -> d) -> *) (x :: LoT d) where
E :: forall (t :: k) d (f :: LoT (k -> d) -> *) (x :: LoT d)
. f (t ':&&: x) -> E f x
-- THE TYPE CLASS
-- | Representable types of any kind. The definition of an instance must
-- mention the type constructor along with a list of types of the corresponding
-- length. For example:
--
-- > instance GenericK Int LoT0
-- > instance GenericK [] (a :&&: LoT0)
-- > instance GenericK Either (a :&&: b :&&: LoT0)
class GenericK (f :: k) (x :: LoT k) where
type RepK f :: LoT k -> *
-- | Convert the data type to its representation.
fromK :: f :@@: x -> RepK f x
default
fromK :: (Generic (f :@@: x), Conv (Rep (f :@@: x)) (RepK f) x)
=> f :@@: x -> RepK f x
fromK = toKindGenerics . from
-- | Convert from a representation to its corresponding data type.
toK :: RepK f x -> f :@@: x
default
toK :: (Generic (f :@@: x), Conv (Rep (f :@@: x)) (RepK f) x)
=> RepK f x -> f :@@: x
toK = to . toGhcGenerics
type GenericF t f x = (GenericK f x, x ~ (SplitF t f), t ~ (f :@@: x))
fromF :: forall f t x. GenericF t f x => t -> RepK f x
fromF = fromK @_ @f
toF :: forall f t x. GenericF t f x => RepK f x -> t
toF = toK @_ @f
type GenericN n t f x = (GenericK f x, 'TyEnv f x ~ (SplitN n t), t ~ (f :@@: x))
fromN :: forall n t f x. GenericN n t f x => t -> RepK f x
fromN = fromK @_ @f
toN :: forall n t f x. GenericN n t f x => RepK f x -> t
toN = toK @_ @f
-- | @GenericS t f x@ states that the ground type @t@ is split by
-- default as the constructor @f@ and a list of types @x$, and that
-- a 'GenericK' instance exists for that constructor.
--
-- This constraint provides an external interface similar to that
-- provided by 'Generic' in "GHC.Generics".
type GenericS t f x = (Split t f x, GenericK f x)
fromS :: forall t f x. GenericS t f x => t -> RepK f x
fromS = fromF @f
toS :: forall t f x. GenericS t f x => RepK f x -> t
toS = toF @f
-- CONVERSION BETWEEN GHC.GENERICS AND KIND-GENERICS
-- | Bridges a representation of a data type using the combinators
-- in "GHC.Generics" with a representation using this module.
-- You are never expected to manipulate this type class directly,
-- it is part of the deriving mechanism for 'GenericK'.
class Conv (gg :: * -> *) (kg :: LoT d -> *) (tys :: LoT d) where
toGhcGenerics :: kg tys -> gg a
toKindGenerics :: gg a -> kg tys
instance Conv U1 U1 tys where
toGhcGenerics U1 = U1
toKindGenerics U1 = U1
instance (Conv f f' tys, Conv g g' tys) => Conv (f :+: g) (f' :+: g') tys where
toGhcGenerics (L1 x) = L1 (toGhcGenerics x)
toGhcGenerics (R1 x) = R1 (toGhcGenerics x)
toKindGenerics (L1 x) = L1 (toKindGenerics x)
toKindGenerics (R1 x) = R1 (toKindGenerics x)
instance (Conv f f' tys, Conv g g' tys) => Conv (f :*: g) (f' :*: g') tys where
toGhcGenerics (x :*: y) = toGhcGenerics x :*: toGhcGenerics y
toKindGenerics (x :*: y) = toKindGenerics x :*: toKindGenerics y
instance {-# OVERLAPPABLE #-} (Conv f f' tys) => Conv (M1 i c f) f' tys where
toGhcGenerics x = M1 (toGhcGenerics x)
toKindGenerics (M1 x) = toKindGenerics x
instance {-# OVERLAPS #-} (Conv f f' tys) => Conv (M1 i c f) (M1 i c f') tys where
toGhcGenerics (M1 x) = M1 (toGhcGenerics x)
toKindGenerics (M1 x) = M1 (toKindGenerics x)
instance (k ~ Ty t tys, Conv f f' tys)
=> Conv (k GG.:=>: f) (t :=>: f') tys where
toGhcGenerics (C x) = SuchThat (toGhcGenerics x)
toKindGenerics (SuchThat x) = C (toKindGenerics x)
instance (k ~ Ty t tys) => Conv (K1 p k) (F t) tys where
toGhcGenerics (F x) = K1 x
toKindGenerics (K1 x) = F x