module Data.Type.Nat (
Nat(..),
toNatural,
fromNatural,
cata,
explicitShow,
explicitShowsPrec,
SNat(..),
snatToNat,
snatToNatural,
SNatI(..),
reify,
reflect,
reflectToNum,
induction,
induction1,
InlineInduction (..),
inlineInduction,
Plus,
Mult,
zero, one, two, three, four, five,
Zero, One, Two, Three, Four, Five,
proofPlusZeroN,
proofPlusNZero,
proofMultZeroN,
proofMultNZero,
proofMultOneN,
proofMultNOne,
) where
import Data.Nat
import Data.Proxy (Proxy (..))
import Data.Type.Equality
import Numeric.Natural (Natural)
data SNat (n :: Nat) where
SZ :: SNat 'Z
SS :: SNatI n => SNat ('S n)
deriving instance Show (SNat p)
class SNatI (n :: Nat) where snat :: SNat n
instance SNatI 'Z where snat = SZ
instance SNatI n => SNatI ('S n) where snat = SS
reflect :: forall n proxy. SNatI n => proxy n -> Nat
reflect _ = unTagged (induction1 (Tagged Z) (retagMap S) :: Tagged n Nat)
reflectToNum :: forall n m proxy. (SNatI n, Num m) => proxy n -> m
reflectToNum _ = unTagged (induction1 (Tagged 0) (retagMap (1+)) :: Tagged n m)
reify :: forall r. Nat -> (forall n. SNatI n => Proxy n -> r) -> r
reify Z f = f (Proxy :: Proxy 'Z)
reify (S n) f = reify n (\(_p :: Proxy n) -> f (Proxy :: Proxy ('S n)))
snatToNat :: forall n. SNat n -> Nat
snatToNat SZ = Z
snatToNat SS = unTagged (induction1 (Tagged Z) (retagMap S) :: Tagged n Nat)
snatToNatural :: forall n. SNat n -> Natural
snatToNatural SZ = 0
snatToNatural SS = unTagged (induction1 (Tagged 0) (retagMap succ) :: Tagged n Natural)
induction1
:: forall n f a. SNatI n
=> f 'Z a
-> (forall m. SNatI m => f m a -> f ('S m) a)
-> f n a
induction1 z f = go where
go :: forall m. SNatI m => f m a
go = case snat :: SNat m of
SZ -> z
SS -> f go
induction
:: forall n f. SNatI n
=> f 'Z
-> (forall m. SNatI m => f m -> f ('S m))
-> f n
induction z f = go where
go :: forall m. SNatI m => f m
go = case snat :: SNat m of
SZ -> z
SS -> f go
class SNatI n => InlineInduction (n :: Nat) where
inlineInduction1 :: f 'Z a -> (forall m. SNatI m => f m a -> f ('S m) a) -> f n a
instance InlineInduction 'Z where
inlineInduction1 z _ = z
instance InlineInduction n => InlineInduction ('S n) where
inlineInduction1 z f = f (inlineInduction1 z f)
inlineInduction
:: forall n f. InlineInduction n
=> f 'Z
-> (forall m. SNatI m => f m -> f ('S m))
-> f n
inlineInduction z f = unConst' $ inlineInduction1 (Const' z) (Const' . f . unConst')
newtype Const' (f :: Nat -> *) (n :: Nat) a = Const' { unConst' :: f n }
type family Plus (n :: Nat) (m :: Nat) :: Nat where
Plus 'Z m = m
Plus ('S n) m = 'S (Plus n m)
type family Mult (n :: Nat) (m :: Nat) :: Nat where
Mult 'Z m = 'Z
Mult ('S n) m = Plus m (Mult n m)
type Zero = 'Z
type One = 'S Zero
type Two = 'S One
type Three = 'S Two
type Four = 'S Three
type Five = 'S Four
proofPlusZeroN :: Plus Zero n :~: n
proofPlusZeroN = Refl
proofPlusNZero :: SNatI n => Plus n Zero :~: n
proofPlusNZero = getProofPlusNZero $ induction (ProofPlusNZero Refl) step where
step :: forall m. ProofPlusNZero m -> ProofPlusNZero ('S m)
step (ProofPlusNZero Refl) = ProofPlusNZero Refl
newtype ProofPlusNZero n = ProofPlusNZero { getProofPlusNZero :: Plus n Zero :~: n }
proofMultZeroN :: Mult Zero n :~: Zero
proofMultZeroN = Refl
proofMultNZero :: forall n. SNatI n => Proxy n -> Mult n Zero :~: Zero
proofMultNZero _ =
getProofMultNZero (induction (ProofMultNZero Refl) step :: ProofMultNZero n)
where
step :: forall m. ProofMultNZero m -> ProofMultNZero ('S m)
step (ProofMultNZero Refl) = ProofMultNZero Refl
newtype ProofMultNZero n = ProofMultNZero { getProofMultNZero :: Mult n Zero :~: Zero }
proofMultOneN :: SNatI n => Mult One n :~: n
proofMultOneN = proofPlusNZero
proofMultNOne :: SNatI n => Mult n One :~: n
proofMultNOne = getProofMultNOne $ induction (ProofMultNOne Refl) step where
step :: forall m. ProofMultNOne m -> ProofMultNOne ('S m)
step (ProofMultNOne Refl) = ProofMultNOne Refl
newtype ProofMultNOne n = ProofMultNOne { getProofMultNOne :: Mult n One :~: n }
newtype Tagged (n :: Nat) a = Tagged a deriving Show
unTagged :: Tagged n a -> a
unTagged (Tagged a) = a
retagMap :: (a -> b) -> Tagged n a -> Tagged m b
retagMap f = Tagged . f . unTagged