{-# LANGUAGE DataKinds #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Type.Nat.LE.ReflStep (
LEProof (..),
fromZeroSucc,
toZeroSucc,
decideLE,
leZero,
leSucc,
leRefl,
leStep,
leAsym,
leTrans,
leSwap,
leSwap',
leStepL,
lePred,
proofZeroLEZero,
) where
import Data.Type.Dec (Dec (..), Decidable (..), Neg)
import Data.Type.Equality
import Data.Type.Nat
import Data.Void (absurd)
import qualified Data.Type.Nat.LE as ZeroSucc
data LEProof n m where
LERefl :: LEProof n n
LEStep :: LEProof n m -> LEProof n ('S m)
deriving instance Show (LEProof n m)
instance Eq (LEProof n m) where
_ == _ = True
instance Ord (LEProof n m) where
compare _ _ = EQ
fromZeroSucc :: forall n m. SNatI m => ZeroSucc.LEProof n m -> LEProof n m
fromZeroSucc ZeroSucc.LEZero = leZero
fromZeroSucc (ZeroSucc.LESucc p) = case snat :: SNat m of
SS -> leSucc (fromZeroSucc p)
toZeroSucc :: SNatI n => LEProof n m -> ZeroSucc.LEProof n m
toZeroSucc LERefl = ZeroSucc.leRefl
toZeroSucc (LEStep p) = ZeroSucc.leStep (toZeroSucc p)
leZero :: forall n. SNatI n => LEProof 'Z n
leZero = case snat :: SNat n of
SZ -> LERefl
SS -> LEStep leZero
leSucc :: LEProof n m -> LEProof ('S n) ('S m)
leSucc LERefl = LERefl
leSucc (LEStep p) = LEStep (leSucc p)
lePred :: LEProof ('S n) ('S m) -> LEProof n m
lePred LERefl = LERefl
lePred (LEStep LERefl) = LEStep LERefl
lePred (LEStep (LEStep q)) = LEStep (leStepL q)
leRefl :: LEProof n n
leRefl = LERefl
leStep :: LEProof n m -> LEProof n ('S m)
leStep = LEStep
leStepL :: LEProof ('S n) m -> LEProof n m
leStepL LERefl = LEStep LERefl
leStepL (LEStep p) = LEStep (leStepL p)
leAsym :: LEProof n m -> LEProof m n -> n :~: m
leAsym LERefl _ = Refl
leAsym _ LERefl = Refl
leAsym (LEStep p) (LEStep q) = case leAsym (leStepL p) (leStepL q) of
Refl -> Refl
leTrans :: LEProof n m -> LEProof m p -> LEProof n p
leTrans LERefl q = q
leTrans p LERefl = p
leTrans (LEStep p) (LEStep q) = LEStep $ leTrans p $ leStepL q
leSwap :: forall n m. (SNatI n, SNatI m) => Neg (LEProof n m) -> LEProof ('S m) n
leSwap np = case (snat :: SNat m, snat :: SNat n) of
(_, SZ) -> absurd (np leZero)
(SZ, SS) -> leSucc leZero
(SS, SS) -> leSucc $ leSwap $ \p -> np $ leSucc p
leSwap' :: LEProof n m -> LEProof ('S m) n -> void
leSwap' p LERefl = case p of LEStep p' -> leSwap' (leStepL p') LERefl
leSwap' p (LEStep q) = leSwap' (leStepL p) q
decideLE :: forall n m. (SNatI n, SNatI m) => Dec (LEProof n m)
decideLE = case snat :: SNat n of
SZ -> Yes leZero
SS -> caseSnm
where
caseSnm :: forall n' m'. (SNatI n', SNatI m') => Dec (LEProof ('S n') m')
caseSnm = case snat :: SNat m' of
SZ -> No $ \p -> case p of {}
SS -> case decideLE of
Yes p -> Yes (leSucc p)
No p -> No $ \p' -> p (lePred p')
instance (SNatI n, SNatI m) => Decidable (LEProof n m) where
decide = decideLE
proofZeroLEZero :: LEProof n 'Z -> n :~: 'Z
proofZeroLEZero LERefl = Refl