{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ExplicitNamespaces #-} ----------------------------------------------------------------------------- -- | -- Module : Data.Type.Equality -- License : BSD-style (see the LICENSE file in the distribution) -- -- Maintainer : libraries@haskell.org -- Stability : experimental -- Portability : not portable -- -- Definition of propositional equality @(:~:)@. Pattern-matching on a variable -- of type @(a :~: b)@ produces a proof that @a ~ b@. -- -- @since 4.7.0.0 ----------------------------------------------------------------------------- module Data.Type.Equality ( -- * The equality type (:~:)(..), -- * Working with equality sym, trans, castWith, gcastWith, apply, inner, outer, -- * Inferring equality from other types TestEquality(..), -- * Boolean type-level equality type (==) ) where import Data.Maybe import GHC.Enum import GHC.Show import GHC.Read import GHC.Base import Data.Type.Bool infix 4 :~: -- | 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@. -- -- @since 4.7.0.0 data a :~: b where Refl :: a :~: a -- with credit to Conal Elliott for 'ty', Erik Hesselink & Martijn van -- Steenbergen for 'type-equality', Edward Kmett for 'eq', and Gabor Greif -- for 'type-eq' -- | 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 -- | Apply one equality to another, respectively apply :: (f :~: g) -> (a :~: b) -> (f a :~: g b) apply Refl Refl = Refl -- | Extract equality of the arguments from an equality of a applied types inner :: (f a :~: g b) -> (a :~: b) inner Refl = Refl -- | Extract equality of type constructors from an equality of applied types outer :: (f a :~: g b) -> (f :~: g) outer Refl = Refl deriving instance Eq (a :~: b) deriving instance Show (a :~: b) deriving instance Ord (a :~: b) instance a ~ b => Read (a :~: b) where readsPrec d = readParen (d > 10) (\r -> [(Refl, s) | ("Refl",s) <- lex r ]) 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 -- | 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 -- | A type family to compute Boolean equality. Instances are provided -- only for /open/ kinds, such as @*@ and function kinds. Instances are -- also provided for datatypes exported from base. A poly-kinded instance -- is /not/ provided, as a recursive definition for algebraic kinds is -- generally more useful. type family (a :: k) == (b :: k) :: Bool infix 4 == {- This comment explains more about why a poly-kinded instance for (==) is not provided. To be concrete, here would be the poly-kinded instance: type family EqPoly (a :: k) (b :: k) where EqPoly a a = True EqPoly a b = False type instance (a :: k) == (b :: k) = EqPoly a b Note that this overlaps with every other instance -- if this were defined, it would be the only instance for (==). Now, consider data Nat = Zero | Succ Nat Suppose I want foo :: (Succ n == Succ m) ~ True => ((n == m) :~: True) foo = Refl This would not type-check with the poly-kinded instance. `Succ n == Succ m` quickly becomes `EqPoly (Succ n) (Succ m)` but then is stuck. We don't know enough about `n` and `m` to reduce further. On the other hand, consider this: type family EqNat (a :: Nat) (b :: Nat) where EqNat Zero Zero = True EqNat (Succ n) (Succ m) = EqNat n m EqNat n m = False type instance (a :: Nat) == (b :: Nat) = EqNat a b With this instance, `foo` type-checks fine. `Succ n == Succ m` becomes `EqNat (Succ n) (Succ m)` which becomes `EqNat n m`. Thus, we can conclude `(n == m) ~ True` as desired. So, the Nat-specific instance allows strictly more reductions, and is thus preferable to the poly-kinded instance. But, if we introduce the poly-kinded instance, we are barred from writing the Nat-specific instance, due to overlap. Even better than the current instance for * would be one that does this sort of recursion for all datatypes, something like this: type family EqStar (a :: *) (b :: *) where EqStar Bool Bool = True EqStar (a,b) (c,d) = a == c && b == d EqStar (Maybe a) (Maybe b) = a == b ... EqStar a b = False The problem is the (...) is extensible -- we would want to add new cases for all datatypes in scope. This is not currently possible for closed type families. -} -- all of the following closed type families are local to this module type family EqStar (a :: *) (b :: *) where EqStar a a = 'True EqStar a b = 'False -- This looks dangerous, but it isn't. This allows == to be defined -- over arbitrary type constructors. type family EqArrow (a :: k1 -> k2) (b :: k1 -> k2) where EqArrow a a = 'True EqArrow a b = 'False type family EqBool a b where EqBool 'True 'True = 'True EqBool 'False 'False = 'True EqBool a b = 'False type family EqOrdering a b where EqOrdering 'LT 'LT = 'True EqOrdering 'EQ 'EQ = 'True EqOrdering 'GT 'GT = 'True EqOrdering a b = 'False type EqUnit (a :: ()) (b :: ()) = 'True type family EqList a b where EqList '[] '[] = 'True EqList (h1 ': t1) (h2 ': t2) = (h1 == h2) && (t1 == t2) EqList a b = 'False type family EqMaybe a b where EqMaybe 'Nothing 'Nothing = 'True EqMaybe ('Just x) ('Just y) = x == y EqMaybe a b = 'False type family Eq2 a b where Eq2 '(a1, b1) '(a2, b2) = a1 == a2 && b1 == b2 type family Eq3 a b where Eq3 '(a1, b1, c1) '(a2, b2, c2) = a1 == a2 && b1 == b2 && c1 == c2 type family Eq4 a b where Eq4 '(a1, b1, c1, d1) '(a2, b2, c2, d2) = a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2 type family Eq5 a b where Eq5 '(a1, b1, c1, d1, e1) '(a2, b2, c2, d2, e2) = a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2 && e1 == e2 type family Eq6 a b where Eq6 '(a1, b1, c1, d1, e1, f1) '(a2, b2, c2, d2, e2, f2) = a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2 && e1 == e2 && f1 == f2 type family Eq7 a b where Eq7 '(a1, b1, c1, d1, e1, f1, g1) '(a2, b2, c2, d2, e2, f2, g2) = a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2 && e1 == e2 && f1 == f2 && g1 == g2 type family Eq8 a b where Eq8 '(a1, b1, c1, d1, e1, f1, g1, h1) '(a2, b2, c2, d2, e2, f2, g2, h2) = a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2 && e1 == e2 && f1 == f2 && g1 == g2 && h1 == h2 type family Eq9 a b where Eq9 '(a1, b1, c1, d1, e1, f1, g1, h1, i1) '(a2, b2, c2, d2, e2, f2, g2, h2, i2) = a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2 && e1 == e2 && f1 == f2 && g1 == g2 && h1 == h2 && i1 == i2 type family Eq10 a b where Eq10 '(a1, b1, c1, d1, e1, f1, g1, h1, i1, j1) '(a2, b2, c2, d2, e2, f2, g2, h2, i2, j2) = a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2 && e1 == e2 && f1 == f2 && g1 == g2 && h1 == h2 && i1 == i2 && j1 == j2 type family Eq11 a b where Eq11 '(a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1) '(a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2) = a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2 && e1 == e2 && f1 == f2 && g1 == g2 && h1 == h2 && i1 == i2 && j1 == j2 && k1 == k2 type family Eq12 a b where Eq12 '(a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1) '(a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2, l2) = a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2 && e1 == e2 && f1 == f2 && g1 == g2 && h1 == h2 && i1 == i2 && j1 == j2 && k1 == k2 && l1 == l2 type family Eq13 a b where Eq13 '(a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1) '(a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2, l2, m2) = a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2 && e1 == e2 && f1 == f2 && g1 == g2 && h1 == h2 && i1 == i2 && j1 == j2 && k1 == k2 && l1 == l2 && m1 == m2 type family Eq14 a b where Eq14 '(a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1) '(a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2, l2, m2, n2) = a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2 && e1 == e2 && f1 == f2 && g1 == g2 && h1 == h2 && i1 == i2 && j1 == j2 && k1 == k2 && l1 == l2 && m1 == m2 && n1 == n2 type family Eq15 a b where Eq15 '(a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1) '(a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2, l2, m2, n2, o2) = a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2 && e1 == e2 && f1 == f2 && g1 == g2 && h1 == h2 && i1 == i2 && j1 == j2 && k1 == k2 && l1 == l2 && m1 == m2 && n1 == n2 && o1 == o2 -- these all look to be overlapping, but they are differentiated by their kinds type instance a == b = EqStar a b type instance a == b = EqArrow a b type instance a == b = EqBool a b type instance a == b = EqOrdering a b type instance a == b = EqUnit a b type instance a == b = EqList a b type instance a == b = EqMaybe a b type instance a == b = Eq2 a b type instance a == b = Eq3 a b type instance a == b = Eq4 a b type instance a == b = Eq5 a b type instance a == b = Eq6 a b type instance a == b = Eq7 a b type instance a == b = Eq8 a b type instance a == b = Eq9 a b type instance a == b = Eq10 a b type instance a == b = Eq11 a b type instance a == b = Eq12 a b type instance a == b = Eq13 a b type instance a == b = Eq14 a b type instance a == b = Eq15 a b