{-# LANGUAGE GADTs #-} -- | Natural numbers inductivey defined at the type-level, and of kind @*@. module Language.Symantic.Typing.Peano where import Data.Type.Equality -- * Types 'Zero' and 'Succ' data Zero data Succ p -- ** Type synonyms for a few numbers type P0 = Zero type P1 = Succ P0 type P2 = Succ P1 type P3 = Succ P2 -- ... -- * Type 'SPeano' -- | Singleton for 'Zero' and 'Succ'. data SPeano p where SZero :: SPeano Zero SSucc :: SPeano p -> SPeano (Succ p) instance TestEquality SPeano where testEquality SZero SZero = Just Refl testEquality (SSucc x) (SSucc y) | Just Refl <- testEquality x y = Just Refl testEquality _ _ = Nothing -- * Type 'IPeano' -- | Implicit construction of 'SPeano'. class IPeano p where ipeano :: SPeano p instance IPeano Zero where ipeano = SZero instance IPeano p => IPeano (Succ p) where ipeano = SSucc ipeano -- * Type 'EPeano' data EPeano where EPeano :: SPeano p -> EPeano instance Eq EPeano where EPeano x == EPeano y = case testEquality x y of Just _ -> True _ -> False instance Show EPeano where show (EPeano x) = show (integral_from_peano x::Integer) -- * Interface with 'Integral' integral_from_peano :: Integral i => SPeano p -> i integral_from_peano SZero = 0 integral_from_peano (SSucc x) = 1 + integral_from_peano x peano_from_integral :: Integral i => i -> (forall p. SPeano p -> ret) -> ret peano_from_integral 0 k = k SZero peano_from_integral i k | i > 0 = peano_from_integral (i - 1) $ \p -> k (SSucc p) peano_from_integral _ _ = error "peano_from_integral" {- -- | /Type-level natural number/, inductively defined. data Nat = Z | S Nat data SNat n where SNatZ :: SNat 'Z SNatS :: SNat n -> SNat ('S n) instance Show (SNat n) where showsPrec _p = showsPrec 10 . intNat intNat :: SNat n -> Int intNat = go 0 where go :: Int -> SNat n -> Int go i SNatZ = i go i (SNatS n) = go (1 + i) n type family (+) (a::Nat) (b::Nat) :: Nat where 'Z + b = b 'S a + b = 'S (a + b) -}