quox/stdlib/nat.quox

298 lines
8.8 KiB
Plaintext
Raw Normal View History

2024-05-06 13:24:02 -04:00
load "misc.quox"
load "bool.quox"
load "either.quox"
load "sub.quox"
namespace nat {
def elim-0-1 :
0.(P : → ★) →
ω.(P 0) → ω.(P 1) →
ω.(0.(n : ) → P n → P (succ n)) →
(n : ) → P n =
λ P p0 p1 ps n ⇒
case n return n' ⇒ P n' of {
zero ⇒ p0;
succ n' ⇒
case n' return n'' ⇒ P (succ n'') of {
zero ⇒ p1;
succ n'', IH ⇒ ps (succ n'') IH
}
}
def elim-pair :
0.(P : → ★) →
ω.(P 0 0) →
ω.(0.(n : ) → P 0 n → P 0 (succ n)) →
ω.(0.(m : ) → P m 0 → P (succ m) 0) →
ω.(0.(m n : ) → P m n → P (succ m) (succ n)) →
(m n : ) → P m n =
λ P zz zs sz ss m ⇒
case m return m' ⇒ (n : ) → P m' n of {
0 ⇒ λ n ⇒ case n return n' ⇒ P 0 n' of {
0 ⇒ zz;
succ n', ihn ⇒ zs n' ihn
};
succ m', ihm ⇒ λ n ⇒ case n return n' ⇒ P (succ m') n' of {
0 ⇒ sz m' (ihm 0);
succ n' ⇒ ss m' n' (ihm n')
}
}
def elim-pairω :
0.(P : → ★) →
ω.(P 0 0) →
ω.(ω.(n : ) → ω.(P 0 n) → P 0 (succ n)) →
ω.(ω.(m : ) → ω.(P m 0) → P (succ m) 0) →
ω.(ω.(m n : ) → ω.(P m n) → P (succ m) (succ n)) →
ω.(m n : ) → P m n =
λ P zz zs sz ss m ⇒
caseω m return m' ⇒ ω.(n : ) → P m' n of {
0 ⇒ λ n ⇒ caseω n return n' ⇒ P 0 n' of {
0 ⇒ zz;
succ n', ω.ihn ⇒ zs n' ihn
};
succ m', ω.ihm ⇒ λ n ⇒ caseω n return n' ⇒ P (succ m') n' of {
0 ⇒ sz m' (ihm 0);
succ n' ⇒ ss m' n' (ihm n')
}
}
def succ-boxω : [ω.] → [ω.] =
λ n ⇒ case n return [ω.] of { [n] ⇒ [succ n] }
#[compile-scheme "(lambda (n) n)"]
def dup : → [ω.] =
λ n ⇒ case n return [ω.] of {
0 ⇒ [0];
succ _, n! ⇒ succ-boxω n!
}
def0 dup-ok : (n : ) → dup n ≡ [n] : [ω.] =
λ n ⇒
case n return n' ⇒ dup n' ≡ [n'] : [ω.] of {
0 ⇒ δ 𝑖 ⇒ [0];
succ _, ih ⇒ δ 𝑖 ⇒ succ-boxω (ih @𝑖)
}
def dup! : (n : ) → Dup n =
dup.from-parts dup dup-ok
def drop : 0.(A : ★) → → A → A =
dup.to-drop dup
def natopω' : 0.(A : ★) → ω.(ω. → ω. → A) → → A =
λ A f m n ⇒
getω A (app2ω A f (dup m) (dup n))
def natopω = natopω'
#[compile-scheme "(lambda% (m n) (+ m n))"]
def plus : =
λ m n ⇒
case m return of {
zero ⇒ n;
succ _, p ⇒ succ p
}
#[compile-scheme "(lambda% (m n) (* m n))"]
def timesω : ω. → ω. =
λ m n ⇒
case m return of {
zero ⇒ zero;
succ _, t ⇒ plus n t
}
def times = natopω timesω
def pred : = λ n ⇒ case n return of { zero ⇒ zero; succ n ⇒ n }
def pred-succ : ω.(n : ) → pred (succ n) ≡ n : =
λ n ⇒ δ 𝑖 ⇒ n
def succ-inj : 0.(m n : ) → succ m ≡ succ n : → m ≡ n : =
λ m n eq ⇒ δ 𝑖 ⇒ pred (eq @𝑖)
#[compile-scheme "(lambda% (m n) (max 0 (- m n)))"]
def minus : =
λ m n ⇒
(case n return of {
zero ⇒ λ m ⇒ m;
succ _, f ⇒ λ m ⇒ f (pred m)
}) m
def minω : ω. → ω. =
elim-pairω (λ _ _ ⇒ ) 0 (λ _ _ ⇒ 0) (λ _ _ ⇒ 0) (λ _ _ x ⇒ succ x)
def min = natopω minω
def0 IsSucc : → ★ =
λ n ⇒ case n return ★ of { zero ⇒ False; succ _ ⇒ True }
def is-succ? : ω.(n : ) → Dec (IsSucc n) =
λ n ⇒
caseω n return n' ⇒ Dec (IsSucc n') of {
zero ⇒ No (IsSucc zero) (λ v ⇒ v);
succ n ⇒ Yes (IsSucc (succ n)) 'true
}
def zero-not-succ : 0.(m : ) → Not (zero ≡ succ m : ) =
λ m eq ⇒ coe (𝑖 ⇒ IsSucc (eq @𝑖)) @1 @0 'true
def succ-not-zero : 0.(m : ) → Not (succ m ≡ zero : ) =
λ m eq ⇒ coe (𝑖 ⇒ IsSucc (eq @𝑖)) 'true
def0 not-succ-self : (m : ) → Not (m ≡ succ m : ) =
λ m ⇒
case m return m' ⇒ Not (m' ≡ succ m' : ) of {
zero ⇒ zero-not-succ 0;
succ n, ω.ih ⇒ λ eq ⇒ ih (succ-inj n (succ n) eq)
}
def0 IsSuccOf : → ★ =
λ n p ⇒ n ≡ succ p :
def0 PredOf : → ★ =
λ n ⇒ Sub (IsSuccOf n)
def0 no-pred0 : Not (PredOf 0) =
λ p ⇒
case p return False of { (p, lt) ⇒
zero-not-succ p (get0 (0 ≡ succ p : ) lt)
}
def pred? : (n : ) → DecT (PredOf n) =
λ n ⇒
case n return n' ⇒ DecT (PredOf n') of {
zero ⇒ NoT (PredOf zero) no-pred0;
succ n ⇒ YesT (PredOf (succ n)) (n, [δ _ ⇒ succ n])
}
namespace pred-of {
def revive : (n : ) → 0.(PredOf n) → PredOf n =
λ n hs ⇒
let0 p = fst hs in
case n return n' ⇒ 0.(n' ≡ succ p : ) → PredOf n' of {
zero ⇒ λ eq ⇒ void (PredOf zero) (zero-not-succ p eq);
succ p' ⇒ λ _ ⇒ (p', [δ _ ⇒ succ p'])
} (get0 (n ≡ succ p : ) (snd hs))
def val : 0.(n : ) → PredOf n → =
λ n ⇒ sub.val (IsSuccOf n)
def0 proof : (n : ) → (p : PredOf n) → n ≡ succ (fst p) : =
λ n ⇒ sub.proof (IsSuccOf n)
}
def divmodω : ω. → ω. × =
-- https://coq.inria.fr/doc/V8.18.0/stdlib/Coq.Init.Nat.html#divmod
letω divmod' : → ω. × =
λ x ⇒
case x return ω. × of {
0 ⇒ λ y q u ⇒ (q, u);
succ _, f' ⇒ λ y q u ⇒
case u return × of {
0 ⇒ f' y (succ q) y;
succ u' ⇒ f' y q u'
}
} in
λ x y ⇒
caseω y return × of {
0 ⇒ (0, 0);
succ y' ⇒
case divmod' x y' 0 y' return × of { (d, m) ⇒ (d, minus y' m) }
}
def divmod = natopω' ( × ) divmodω
def divω : ω. → ω. = λ x y ⇒ fst (divmodω x y)
def div = natopω divω
def modω : ω. → ω. = λ x y ⇒ snd (divmodω x y)
def mod = natopω modω
#[compile-scheme "(lambda% (m n) (if (= m n) Yes No))"]
def eq? : DecEq =
λ m n ⇒
elim-pair (λ m n ⇒ Dec (m ≡ n : ))
(Yes (0 ≡ 0 : ) (δ 𝑖 ⇒ 0))
(λ n p ⇒
dec.drop (0 ≡ n : ) (Dec (0 ≡ succ n : )) p
(No (0 ≡ succ n : ) (λ zs ⇒ zero-not-succ n zs)))
(λ m p ⇒
dec.drop (m ≡ 0 : ) (Dec (succ m ≡ 0 : )) p
(No (succ m ≡ 0 : ) (λ sz ⇒ succ-not-zero m sz)))
(λ m n ⇒
dec.elim (m ≡ n : ) (λ _ ⇒ Dec (succ m ≡ succ n : ))
(λ yy ⇒ Yes (succ m ≡ succ n : ) (δ 𝑖 ⇒ succ (yy @𝑖)))
(λ nn ⇒ No (succ m ≡ succ n : ) (λ yy ⇒ nn (succ-inj m n yy))))
m n
def0 Ordering : ★ = {lt, eq, gt}
namespace ordering {
def from : 0.(A : ★) → ω.A → ω.A → ω.A → Ordering → A =
λ A lt eq gt o ⇒
case o return A of { 'lt ⇒ lt; 'eq ⇒ eq; 'gt ⇒ gt }
def drop : 0.(A : ★) → Ordering → A → A =
λ A o x ⇒ case o return A of { 'lt ⇒ x; 'eq ⇒ x; 'gt ⇒ x }
def eq : Ordering → Ordering → Bool =
λ x y ⇒
case x return Bool of {
'lt ⇒ case y return Bool of { 'lt ⇒ 'true; 'eq ⇒ 'false; 'gt ⇒ 'false };
'eq ⇒ case y return Bool of { 'lt ⇒ 'false; 'eq ⇒ 'true; 'gt ⇒ 'false };
'gt ⇒ case y return Bool of { 'lt ⇒ 'false; 'eq ⇒ 'false; 'gt ⇒ 'true };
}
}
def compare : → Ordering =
elim-pair (λ _ _ ⇒ Ordering)
'eq
(λ _ o ⇒ ordering.drop Ordering o 'lt)
(λ _ o ⇒ ordering.drop Ordering o 'gt)
(λ _ _ x ⇒ x)
def lt : ω. → ω. → Bool = λ m n ⇒ ordering.eq (compare m n) 'lt
def eq : ω. → ω. → Bool = λ m n ⇒ ordering.eq (compare m n) 'eq
def gt : ω. → ω. → Bool = λ m n ⇒ ordering.eq (compare m n) 'gt
def ne : ω. → ω. → Bool = λ m n ⇒ bool.not (eq m n)
def le : ω. → ω. → Bool = λ m n ⇒ bool.not (gt m n)
def ge : ω. → ω. → Bool = λ m n ⇒ bool.not (lt m n)
def0 plus-zero : (m : ) → m ≡ plus m 0 : =
λ m ⇒
case m return m' ⇒ m' ≡ plus m' 0 : of {
zero ⇒ δ _ ⇒ 0;
succ m', ih ⇒ δ 𝑖 ⇒ succ (ih @𝑖)
}
def0 plus-succ : (m n : ) → succ (plus m n) ≡ plus m (succ n) : =
λ m n ⇒
case m return m' ⇒ succ (plus m' n) ≡ plus m' (succ n) : of {
zero ⇒ δ _ ⇒ succ n;
succ _, ih ⇒ δ 𝑖 ⇒ succ (ih @𝑖)
}
def0 times-zero : (m : ) → 0 ≡ timesω m 0 : =
λ m ⇒
case m return m' ⇒ 0 ≡ timesω m' 0 : of {
zero ⇒ δ _ ⇒ zero;
succ m', ih ⇒ ih
}
}