-- without recursion, computation is kind of hard -- we can, however, define natural numbers using the Church encoding and do -- computation with them -- the natural number `n` is encoded as the function taking any function -- `A -> A` and repeating it `n` times def nat : * := forall (A : *), (A -> A) -> A -> A; -- zero is the constant function def zero : nat := fun (A : *) (f : A -> A) (x : A) => x; -- `suc n` composes one more `f` than `n` def suc : nat -> nat := fun (n : nat) (A : *) (f : A -> A) (x : A) => f ((n A f) x); -- addition can be encoded as usual def plus : nat -> nat -> nat := fun (n m : nat) (A : *) (f : A -> A) (x : A) => (m A f) (n A f x); -- likewise for multiplication def times : nat -> nat -> nat := fun (n m : nat) (A : *) (f : A -> A) (x : A) => (m A (n A f)) x; -- unforunately, it is impossible to prove induction on Church numerals, -- which makes it really hard to prove standard theorems, or do anything really. -- but we can still do computations with Church numerals -- first some abbreviations for numbers will be handy def one : nat := suc zero; def two : nat := suc one; def three : nat := suc two; def four : nat := suc three; def five : nat := suc four; def six : nat := suc five; def seven : nat := suc six; def eight : nat := suc seven; def nine : nat := suc eight; def ten : nat := suc nine; -- now we can do a bunch of computations, even at the type level -- the way we can do this is by defining equality (see for -- more details on how this works) and proving a bunch of theorems like -- `plus one one = two` (how exciting!) -- then perga will only accept our proof if `plus one one` and `two` are beta -- equivalent -- first we do need a definition of equality def eq (A : *) (x y : A) := forall (P : A -> *), P x -> P y; def eq_refl (A : *) (x : A) : eq A x x := fun (P : A -> *) (Hx : P x) => Hx; def eq_sym (A : *) (x y : A) (Hxy : eq A x y) : eq A y x := fun (P : A -> *) (Hy : P y) => Hxy (fun (z : A) => P z -> P x) (fun (Hx : P x) => Hx) Hy; def eq_trans (A : *) (x y z : A) (Hxy : eq A x y) (Hyz : eq A y z) : eq A x z := fun (P : A -> *) (Hx : P x) => Hyz P (Hxy P Hx); def eq_cong (A B : *) (x y : A) (f : A -> B) (H : eq A x y) : eq B (f x) (f y) := fun (P : B -> *) (Hfx : P (f x)) => H (fun (a : A) => P (f a)) Hfx; -- since `plus one one` and `two` are beta-equivalent, `eq_refl nat two` is a -- proof that `1 + 1 = 2` def one_plus_one_is_two : eq nat (plus one one) two := eq_refl nat two; -- we can likewise compute 2 + 2 def two_plus_two_is_four : eq nat (plus two two) four := eq_refl nat four; -- even multiplication works def two_times_five_is_ten : eq nat (times two five) ten := eq_refl nat ten;