{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE FlexibleContexts #-}
module Type.Data.Num.Unary.Proof (
Nat(..), Pos(..),
natFromPos,
addNat, addPosL, addPosR,
AddZeroL(..), addZeroL,
AddComm(..), addComm,
AddAssoc(..), addAssoc,
mulNat, mulPos,
) where
import Type.Data.Num.Unary
(Natural, Positive, Zero, Succ, switchNat, switchPos, (:+:), (:*:))
data Nat x = Natural x => Nat
data Pos x = Positive x => Pos
succNat :: Nat x -> Nat (Succ x)
succNat Nat = Nat
prevNat :: (Natural x) => Nat (Succ x) -> Nat x
prevNat Nat = Nat
posSucc :: Nat x -> Pos (Succ x)
posSucc Nat = Pos
prevPos :: (Natural x) => Pos (Succ x) -> Nat x
prevPos Pos = Nat
natFromPos :: Pos x -> Nat x
natFromPos Pos = Nat
newtype
QuantifiedAdd condx condy prop x y =
QuantifiedAdd {runQuantifiedAdd :: condx x -> condy y -> prop (x :+: y)}
addNat :: Nat x -> Nat y -> Nat (x :+: y)
addNat x0 y0@Nat =
runQuantifiedAdd
(switchNat
(QuantifiedAdd const)
(QuantifiedAdd $ \x -> succNat . addNat x . prevNat))
x0 y0
addPosR :: Nat x -> Pos y -> Pos (x :+: y)
addPosR x0 y0@Pos =
runQuantifiedAdd
(switchPos (QuantifiedAdd $ \x -> posSucc . addNat x . prevPos))
x0 y0
addPosL :: Pos x -> Nat y -> Pos (x :+: y)
addPosL x0 y0@Nat =
runQuantifiedAdd
(switchNat
(QuantifiedAdd const)
(QuantifiedAdd $ \x -> posSucc . addNat (natFromPos x) . prevNat))
x0 y0
newtype Quantified prop x = Quantified {runQuantified :: Nat x -> prop x}
induction ::
quant Zero -> (forall x. Nat x -> quant (Succ x)) ->
Nat y -> quant y
induction base step y@Nat =
runQuantified
(switchNat
(Quantified $ const base)
(Quantified $ step . prevNat))
y
data AddZeroL x = (Zero:+:x) ~ x => AddZeroL
succZeroL :: AddZeroL x -> AddZeroL (Succ x)
succZeroL AddZeroL = AddZeroL
addZeroL :: Nat x -> AddZeroL x
addZeroL = induction AddZeroL (succZeroL . addZeroL)
data AddSuccL x y = (Succ x :+: y) ~ Succ (x:+:y) => AddSuccL
succSuccL :: AddSuccL x y -> AddSuccL x (Succ y)
succSuccL AddSuccL = AddSuccL
addSuccL :: Nat x -> Nat y -> AddSuccL x y
addSuccL x =
induction
(case addZeroL x of AddZeroL -> AddSuccL)
(succSuccL . addSuccL x)
data AddComm x y = (x:+:y) ~ (y:+:x) => AddComm
succComm :: Nat x -> Nat y -> AddComm x y -> AddComm x (Succ y)
succComm x y AddComm = case addSuccL y x of AddSuccL -> AddComm
addComm :: Nat x -> Nat y -> AddComm x y
addComm x =
induction
(case addZeroL x of AddZeroL -> AddComm)
(\y -> succComm x y $ addComm x y)
data AddAssoc x y z = (x:+:(y:+:z)) ~ ((x:+:y):+:z) => AddAssoc
succAssoc :: AddAssoc x y z -> AddAssoc x y (Succ z)
succAssoc AddAssoc = AddAssoc
addAssoc :: Nat x -> Nat y -> Nat z -> AddAssoc x y z
addAssoc x y = induction AddAssoc (succAssoc . addAssoc x y)
newtype
QuantifiedMul condx condy prop x y =
QuantifiedMul {runQuantifiedMul :: condx x -> condy y -> prop (x :*: y)}
mulNat :: Nat x -> Nat y -> Nat (x :*: y)
mulNat x0 y0@Nat =
runQuantifiedMul
(switchNat
(QuantifiedMul $ \Nat Nat -> Nat)
(QuantifiedMul $ \x -> addNat x . mulNat x . prevNat))
x0 y0
mulPos :: Pos x -> Pos y -> Pos (x :*: y)
mulPos x0 y0@Pos =
runQuantifiedMul
(switchPos
(QuantifiedMul $ \x -> addPosL x . mulNat (natFromPos x) . prevPos))
x0 y0