type-equality-1: src-old/Data/Type/Equality.hs
{-# LANGUAGE CPP #-}
#if __GLASGOW_HASKELL__ >= 708
#error "Trying to compiled Data.Type.Equality module with GHC-7.8+"
#endif
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
#if __GLASGOW_HASKELL__ >= 706
{-# LANGUAGE PolyKinds #-}
#endif
#if __GLASGOW_HASKELL__ >= 702
-- only Trustworthy, as we have manual Typeable instance
{-# LANGUAGE Trustworthy #-}
#endif
module Data.Type.Equality (
-- * Type equality
(:~:) (..),
-- * Combinators
sym,
trans,
castWith,
gcastWith,
#if __GLASGOW_HASKELL__ >= 706
apply,
#endif
inner,
#if __GLASGOW_HASKELL__ >= 706
outer,
#endif
-- inner and outer not implemented,
-- as GHC-7.6 fails to infer them:
-- Could not deduce (f ~ g) from the context (f a ~ g b)
-- There are no (==) as it needs ClosedTypeFamilies (since GHC-7.8)
-- * TestEquality
--
-- | Provided only for GHC-7.6.
-- Also there isn't @==@ type family, as it requires close type families,
-- which are available only since GHC-7.8.
TestEquality (..),
) where
import qualified Control.Category as C
import Data.Typeable (Typeable2 (..), Typeable)
import Data.Data (Data (..), Constr, mkConstr, Fixity(Prefix), DataType, mkDataType, mkTyConApp, TyCon)
#if MIN_VERSION_base(4,4,0)
import Data.Data (mkTyCon3)
#else
import Data.Data (mkTyCon)
#endif
#ifndef CURRENT_PACKAGE_KEY
import Data.Version (showVersion)
import Paths_type_equality_compat (version)
#endif
-- | Propositional equality. If @a ':~:' b@ is inhabited by some
-- terminating value, then the type @a@ is the same as the type
-- @b@. To use this equality in practice, pattern-match on the
-- @a ':~:' b@ to get out the 'Refl' constructor; in the body of
-- the pattern-match, the compiler knows that @a ~ b@.
--
-- /Note:/ this definition is polykinded only since GHC-7.6.
--
data a :~: b where
Refl :: a :~: a
deriving instance Eq (a :~: b)
deriving instance Ord (a :~: b)
deriving instance a ~ b => Read (a :~: b)
deriving instance Show (a :~: b)
instance C.Category (:~:) where
id = Refl
Refl . Refl = Refl
instance a ~ b => Enum (a :~: b) where
toEnum 0 = Refl
toEnum _ = error "Data.Type.Equality.toEnum: bad argument"
fromEnum Refl = 0
instance a ~ b => Bounded (a :~: b) where
minBound = Refl
maxBound = Refl
-------------------------------------------------------------------------------
-- Typeable & Data
-------------------------------------------------------------------------------
instance Typeable2 (:~:) where
typeOf2 _ = mkTyConApp eqTyCon []
typeEqualityCompatPackageKey :: String
#ifdef CURRENT_PACKAGE_KEY
typeEqualityCompatPackageKey = CURRENT_PACKAGE_KEY
#else
typeEqualityCompatPackageKey = "type-equality-compat-" ++ showVersion version
#endif
eqTyCon :: TyCon
#if MIN_VERSION_base(4,4,0)
eqTyCon = mkTyCon3 typeEqualityCompatPackageKey "Data.Type.Equality" ":~:"
#else
eqTyCon = mkTyCon "Data.Type.Equality.:~:"
#endif
instance (Typeable a, Typeable b, a ~ b) => Data (a :~: b) where
gfoldl _ z Refl = z Refl
gunfold _ z _ = z Refl
toConstr Refl = reflConstr
dataTypeOf _ = eqDataType
eqDataType :: DataType
eqDataType = mkDataType ":~:" [reflConstr]
reflConstr :: Constr
reflConstr = mkConstr eqDataType "Refl" [] Prefix
-------------------------------------------------------------------------------
-- Combinators
-------------------------------------------------------------------------------
-- | Symmetry of equality
sym :: (a :~: b) -> (b :~: a)
sym Refl = Refl
-- | Transitivity of equality
trans :: (a :~: b) -> (b :~: c) -> (a :~: c)
trans Refl Refl = Refl
-- | Type-safe cast, using propositional equality
castWith :: (a :~: b) -> a -> b
castWith Refl x = x
-- | Generalized form of type-safe cast using propositional equality
gcastWith :: (a :~: b) -> ((a ~ b) => r) -> r
gcastWith Refl x = x
#if __GLASGOW_HASKELL__ >= 706
-- | Apply one equality to another, respectively
apply :: (f :~: g) -> (a :~: b) -> (f a :~: g b)
apply Refl Refl = Refl
#endif
-- | Extract equality of the arguments from an equality of applied types
inner :: f a :~: g b -> a :~: b
inner = fromLeibniz . innerLeibniz . toLeibniz
#if __GLASGOW_HASKELL__ >= 706
-- | Extract equality of type constructors from an equality of applied types
outer :: f a :~: g b -> f :~: g
outer = fromLeibniz . outerLeibniz . toLeibniz
#endif
-------------------------------------------------------------------------------
-- TestEquality
-------------------------------------------------------------------------------
-- | This class contains types where you can learn the equality of two types
-- from information contained in /terms/. Typically, only singleton types should
-- inhabit this class.
class TestEquality f where
-- | Conditionally prove the equality of @a@ and @b@.
testEquality :: f a -> f b -> Maybe (a :~: b)
instance TestEquality ((:~:) a) where
testEquality Refl Refl = Just Refl
-------------------------------------------------------------------------------
-- Leibniz
-------------------------------------------------------------------------------
newtype a := b = ReflLeibniz { subst :: forall c. c a -> c b }
reflLeibniz :: a := a
reflLeibniz = ReflLeibniz id
#if __GLASGOW_HASKELL__ >= 706
type family Inj (f :: j -> k) (a :: k) :: j
#else
type family Inj (f :: * -> *) (a :: *) :: *
#endif
type instance Inj f (g a) = a
newtype Lower f a b = Lower { unlower :: Inj f a := Inj f b }
fromLeibniz :: a := b -> a :~: b
fromLeibniz a = subst a Refl
toLeibniz :: a :~: b -> a := b
toLeibniz Refl = reflLeibniz
innerLeibniz :: f a := g b -> a := b
innerLeibniz eq = unlower (subst eq (Lower reflLeibniz :: Lower f (f a) (f a)))
#if __GLASGOW_HASKELL__ >= 706
type family Gen (f :: j -> k) (a :: k) :: j -> k
type instance Gen f (g a) = g
newtype Generate f a b = Generate { ungenerate :: Gen f a := Gen f b }
outerLeibniz :: f a := g b -> f := g
outerLeibniz eq = ungenerate (subst eq (Generate reflLeibniz :: Generate f (f a) (f a)))
#endif