basic haskell operator syntax

This commit is contained in:
William Ball 2024-12-10 23:36:34 -08:00
parent 534809bef9
commit e6f9d71c57
7 changed files with 90 additions and 88 deletions

View file

@ -23,7 +23,7 @@ section BasicDefinitions
-- a binary operation is a function `A → A → A` -- a binary operation is a function `A → A → A`
def binop := A → A → A; def binop := A → A → A;
-- fix some binary operation `op` -- fix some binary operation `*`
variable (* : binop); variable (* : binop);
infixl 20 *; infixl 20 *;
@ -64,34 +64,31 @@ def semigroup (S : ★) (op : binop S) : ★ := assoc S op;
section Monoid section Monoid
-- Let `M` be a set with binary operation `op` and element `e`. -- Let `M` be a set with binary operation `*` and element `e`.
variable (M : ★) (op : binop M) (e : M); variable (M : ★) (* : binop M) (e : M);
-- We'll use `*` as an infix shorthand for `op`
def * (a b : M) := op a b;
infixl 50 *; infixl 50 *;
-- a set `M` with binary operation `op` and element `e` is a monoid -- a set `M` with binary operation `(*)` and element `e` is a monoid
def monoid : ★ := (semigroup M op) ∧ (id M op e); def monoid : ★ := (semigroup M (*)) ∧ (id M (*) e);
-- Suppose `(M, *, e)` is a monoid -- Suppose `(M, *, e)` is a monoid
hypothesis (Hmonoid : monoid); hypothesis (Hmonoid : monoid);
-- some "getters" for `monoid` so we don't have to do a bunch of very verbose -- some "getters" for `monoid` so we don't have to do a bunch of very verbose
-- and-eliminations every time we want to use something -- and-eliminations every time we want to use something
def id_lm : id_l M op e := def id_lm : id_l M (*) e :=
and_elim_l (id_l M op e) (id_r M op e) and_elim_l (id_l M (*) e) (id_r M (*) e)
(and_elim_r (semigroup M op) (id M op e) Hmonoid); (and_elim_r (semigroup M (*)) (id M (*) e) Hmonoid);
def id_rm : id_r M op e := def id_rm : id_r M (*) e :=
and_elim_r (id_l M op e) (id_r M op e) and_elim_r (id_l M (*) e) (id_r M (*) e)
(and_elim_r (semigroup M op) (id M op e) Hmonoid); (and_elim_r (semigroup M (*)) (id M (*) e) Hmonoid);
def assoc_m : assoc M op := and_elim_l (semigroup M op) (id M op e) Hmonoid; def assoc_m : assoc M (*) := and_elim_l (semigroup M (*)) (id M (*) e) Hmonoid;
-- now we can prove that, for any monoid, if `a` is a left identity, then it -- now we can prove that, for any monoid, if `a` is a left identity, then it
-- must be "the" identity -- must be "the" identity
def monoid_id_l_implies_identity (a : M) (H : id_l M op a) : eq M a e := def monoid_id_l_implies_identity (a : M) (H : id_l M (*) a) : eq M a e :=
-- WTS a = a * e = e -- WTS a = a * e = e
-- we can use `eq_trans` to glue proofs of `a = a * e` and `a * e = e` together -- we can use `eq_trans` to glue proofs of `a = a * e` and `a * e = e` together
eq_trans M a (a * e) e eq_trans M a (a * e) e
@ -105,7 +102,7 @@ section Monoid
(H e); (H e);
-- the analogous result for right identities -- the analogous result for right identities
def monoid_id_r_implies_identity (a : M) (H : id_r M op a) : eq M a e := def monoid_id_r_implies_identity (a : M) (H : id_r M (*) a) : eq M a e :=
-- this time, we'll show `a = e * a = e` -- this time, we'll show `a = e * a = e`
eq_trans M a (e * a) e eq_trans M a (e * a) e
@ -121,28 +118,27 @@ end Monoid
section Group section Group
variable (G : ★) (op : binop G) (e : G) (i : unop G); variable (G : ★) (* : binop G) (e : G) (i : unop G);
def * (a b : G) := op a b;
infixl 50 *; infixl 50 *;
-- groups are just monoids with inverses -- groups are just monoids with inverses
def has_inverses : ★ := forall (a : G), inv G op e a (i a); def has_inverses : ★ := forall (a : G), inv G (*) e a (i a);
def group : ★ := (monoid G op e) ∧ has_inverses; def group : ★ := (monoid G (*) e) ∧ has_inverses;
hypothesis (Hgroup : group); hypothesis (Hgroup : group);
-- more "getters" -- more "getters"
def monoid_g : monoid G op e := and_elim_l (monoid G op e) has_inverses Hgroup; def monoid_g : monoid G (*) e := and_elim_l (monoid G (*) e) has_inverses Hgroup;
def assoc_g : assoc G op := assoc_m G op e monoid_g; def assoc_g : assoc G (*) := assoc_m G (*) e monoid_g;
def id_lg : id_l G op e := id_lm G op e (and_elim_l (monoid G op e) has_inverses Hgroup); def id_lg : id_l G (*) e := id_lm G (*) e (and_elim_l (monoid G (*) e) has_inverses Hgroup);
def id_rg : id_r G op e := id_rm G op e (and_elim_l (monoid G op e) has_inverses Hgroup); def id_rg : id_r G (*) e := id_rm G (*) e (and_elim_l (monoid G (*) e) has_inverses Hgroup);
def inv_g : forall (a : G), inv G op e a (i a) := and_elim_r (monoid G op e) has_inverses Hgroup; def inv_g : forall (a : G), inv G (*) e a (i a) := and_elim_r (monoid G (*) e) has_inverses Hgroup;
def left_inverse (a b : G) := inv_l G op e a b; def left_inverse (a b : G) := inv_l G (*) e a b;
def right_inverse (a b : G) := inv_r G op e a b; def right_inverse (a b : G) := inv_r G (*) e a b;
def inv_lg (a : G) : left_inverse a (i a) := and_elim_l (inv_l G op e a (i a)) (inv_r G op e a (i a)) (inv_g a); def inv_lg (a : G) : left_inverse a (i a) := and_elim_l (inv_l G (*) e a (i a)) (inv_r G (*) e a (i a)) (inv_g a);
def inv_rg (a : G) : right_inverse a (i a) := and_elim_r (inv_l G op e a (i a)) (inv_r G op e a (i a)) (inv_g a); def inv_rg (a : G) : right_inverse a (i a) := and_elim_r (inv_l G (*) e a (i a)) (inv_r G (*) e a (i a)) (inv_g a);
-- An interesting theorem: left inverses are unique, i.e. if b * a = e, then b = a^-1 -- An interesting theorem: left inverses are unique, i.e. if b * a = e, then b = a^-1
def left_inv_unique (a b : G) (h : left_inverse a b) : eq G b (i a) := def left_inv_unique (a b : G) (h : left_inverse a b) : eq G b (i a) :=
@ -157,7 +153,7 @@ section Group
-- b * e = a^-1 -- b * e = a^-1
(eq_trans G (b * e) (b * (a * i a)) (i a) (eq_trans G (b * e) (b * (a * i a)) (i a)
--b * e = b * (a * a^-1) --b * e = b * (a * a^-1)
(eq_cong G G e (a * i a) (op b) (eq_cong G G e (a * i a) ((*) b)
-- e = a * a^-1 -- e = a * a^-1
(eq_sym G (a * i a) e (inv_rg a))) (eq_sym G (a * i a) e (inv_rg a)))
-- b * (a * a^-1) = a^-1 -- b * (a * a^-1) = a^-1
@ -196,7 +192,7 @@ section Group
-- a^-1 * (a * b) = a^-1 -- a^-1 * (a * b) = a^-1
(eq_trans G (i a * (a * b)) (i a * e) (i a) (eq_trans G (i a * (a * b)) (i a * e) (i a)
-- a^-1 * (a * b) = a^-1 * e -- a^-1 * (a * b) = a^-1 * e
(eq_cong G G (a * b) e (op (i a)) h) (eq_cong G G (a * b) e ((*) (i a)) h)
-- a^-1 * e = a^-1 -- a^-1 * e = a^-1
(id_rg (i a))))); (id_rg (i a)))));

View file

@ -3,13 +3,13 @@
section Category section Category
variable variable
(Obj : ★) (Obj : ★)
(~> : Obj -> Obj -> ★); (~> : Obj → Obj → ★);
infixr 10 ~>; infixr 10 ~>;
variable variable
(id : forall (A : Obj), A ~> A) (id : forall (A : Obj), A ~> A)
(comp : forall (A B C : Obj), A ~> B -> B ~> C -> A ~> C); (comp : forall (A B C : Obj), A ~> B → B ~> C → A ~> C);
hypothesis hypothesis
(id_l : forall (A B : Obj) (f : A ~> B), eq (A ~> B) (comp A A B (id A) f) f) (id_l : forall (A B : Obj) (f : A ~> B), eq (A ~> B) (comp A A B (id A) f) f)

View file

@ -11,7 +11,7 @@ def dne (P : ★) (nnp : not (not P)) : P :=
(fun (np : not P) => nnp np P); (fun (np : not P) => nnp np P);
-- ((P => Q) => P) => P -- ((P => Q) => P) => P
def peirce (P Q : ★) (h : (P -> Q) -> P) : P := def peirce (P Q : ★) (h : (P → Q) → P) : P :=
or_elim P (not P) P (em P) or_elim P (not P) P (em P)
(fun (p : P) => p) (fun (p : P) => p)
(fun (np : not P) => h (fun (p : P) => np p Q)); (fun (np : not P) => h (fun (p : P) => np p Q));

View file

@ -5,21 +5,21 @@
-- computation with them -- computation with them
-- the natural number `n` is encoded as the function taking any function -- the natural number `n` is encoded as the function taking any function
-- `A -> A` and repeating it `n` times -- `A A` and repeating it `n` times
def nat : ★ := forall (A : ★), (A -> A) -> A -> A; def nat : ★ := forall (A : ★), (A → A) → A → A;
-- zero is the constant function -- zero is the constant function
def zero : nat := fun (A : ★) (f : A -> A) (x : A) => x; def zero : nat := fun (A : ★) (f : A A) (x : A) => x;
-- `suc n` composes one more `f` than `n` -- `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); def suc : nat → nat := fun (n : nat) (A : ★) (f : A → A) (x : A) => f ((n A f) x);
-- addition can be encoded as usual -- addition can be encoded as usual
def + : nat -> nat -> nat := fun (n m : nat) (A : ★) (f : A -> A) (x : A) => (m A f) (n A f x); def + : nat → nat → nat := fun (n m : nat) (A : ★) (f : A → A) (x : A) => (m A f) (n A f x);
infixl 20 +; infixl 20 +;
-- likewise for multiplication -- likewise for multiplication
def * : nat -> nat -> nat := fun (n m : nat) (A : ★) (f : A -> A) (x : A) => (m A (n A f)) x; def * : nat → nat → nat := fun (n m : nat) (A : ★) (f : A → A) (x : A) => (m A (n A f)) x;
infixl 30 *; infixl 30 *;
-- unforunately, it is impossible to prove induction on Church numerals, -- unforunately, it is impossible to prove induction on Church numerals,

View file

@ -49,15 +49,15 @@ axiom zero : nat;
axiom suc (n : nat) : nat; axiom suc (n : nat) : nat;
-- axiom 7: If S n = S m, then n = m. -- axiom 7: If S n = S m, then n = m.
axiom suc_inj : forall (n m : nat), eq nat (suc n) (suc m) -> eq nat n m; axiom suc_inj : forall (n m : nat), eq nat (suc n) (suc m) eq nat n m;
-- axiom 8: No successor of any natural number is zero. -- axiom 8: No successor of any natural number is zero.
axiom suc_nonzero : forall (n : nat), not (eq nat (suc n) zero); axiom suc_nonzero : forall (n : nat), not (eq nat (suc n) zero);
-- axiom 9: Induction! For any proposition P on natural numbers, if P(0) holds, -- axiom 9: Induction! For any proposition P on natural numbers, if P(0) holds,
-- and if for every natural number n, P(n) ⇒ P(S n), then P holds for all n. -- and if for every natural number n, P(n) ⇒ P(S n), then P holds for all n.
axiom nat_ind : forall (P : nat -> ★), P zero -> (forall (n : nat), P n -> P (suc n)) axiom nat_ind : forall (P : nat → ★), P zero → (forall (n : nat), P n → P (suc n))
-> forall (n : nat), P n; forall (n : nat), P n;
-- }}} -- }}}
@ -130,8 +130,8 @@ def suc_or_zero : forall (n : nat), szc n :=
-- So, we will take the time to prove the following theorem. -- So, we will take the time to prove the following theorem.
-- --
-- Theorem (recursive definitions): -- Theorem (recursive definitions):
-- For every type A, element z : A, and function fS : nat -> A -> A, there -- For every type A, element z : A, and function fS : nat → A → A, there
-- exists a unique function f : nat -> A satisfying -- exists a unique function f : nat A satisfying
-- 1) f 0 = z -- 1) f 0 = z
-- 2) forall n : nat, f (suc n) = fS n (f n) -- 2) forall n : nat, f (suc n) = fS n (f n)
-- --
@ -146,10 +146,10 @@ def suc_or_zero : forall (n : nat), szc n :=
-- more used to perga. As such, I will go into a lot less detail on each of -- more used to perga. As such, I will go into a lot less detail on each of
-- these proofs than in the later sections. -- these proofs than in the later sections.
-- --
-- Here's our game plan. We will define a relation R : nat -> A -> ★ such that -- Here's our game plan. We will define a relation R : nat → A → ★ such that
-- R x y iff for every relation Q : nat -> A -> ★ satisfying -- R x y iff for every relation Q : nat → A → ★ satisfying
-- 1) Q 0 z and -- 1) Q 0 z and
-- 2) forall (x : nat) (y : A), Q x y -> Q (suc x) (fS x y), -- 2) forall (x : nat) (y : A), Q x y Q (suc x) (fS x y),
-- Q x y. -- Q x y.
-- In more mathy lingo, we take R to be the intersection of every relation -- In more mathy lingo, we take R to be the intersection of every relation
-- satisfying 1 and 2. From there we will, with much effort, prove that R is -- satisfying 1 and 2. From there we will, with much effort, prove that R is
@ -157,31 +157,31 @@ def suc_or_zero : forall (n : nat), szc n :=
section RecursiveDefs section RecursiveDefs
-- First, fix an A, z : A, and fS : nat -> A -> A -- First, fix an A, z : A, and fS : nat → A → A
variable (A : ★) (z : A) (fS : nat -> A -> A); variable (A : ★) (z : A) (fS : nat → A → A);
-- {{{ Defining R -- {{{ Defining R
-- Here is condition 1 formally expressed in perga. -- Here is condition 1 formally expressed in perga.
def cond1 (Q : nat -> A -> ★) := Q zero z; def cond1 (Q : nat → A → ★) := Q zero z;
-- Likewise for condition 2. -- Likewise for condition 2.
def cond2 (Q : nat -> A -> ★) := def cond2 (Q : nat → A → ★) :=
forall (n : nat) (y : A), Q n y -> Q (suc n) (fS n y); forall (n : nat) (y : A), Q n y Q (suc n) (fS n y);
-- From here we can define R. -- From here we can define R.
def rec_rel (x : nat) (y : A) := def rec_rel (x : nat) (y : A) :=
forall (Q : nat -> A -> ★), cond1 Q -> cond2 Q -> Q x y; forall (Q : nat → A → ★), cond1 Q → cond2 Q → Q x y;
-- }}} -- }}}
-- {{{ R is total -- {{{ R is total
def total (A B : ★) (R : A -> B -> ★) := forall (a : A), exists B (R a); def total (A B : ★) (R : A → B → ★) := forall (a : A), exists B (R a);
def rec_rel_cond1 : cond1 rec_rel := def rec_rel_cond1 : cond1 rec_rel :=
fun (Q : nat -> A -> ★) (h1 : cond1 Q) (h2 : cond2 Q) => h1; fun (Q : nat → A → ★) (h1 : cond1 Q) (h2 : cond2 Q) => h1;
def rec_rel_cond2 : cond2 rec_rel := def rec_rel_cond2 : cond2 rec_rel :=
fun (n : nat) (y : A) (h : rec_rel n y) fun (n : nat) (y : A) (h : rec_rel n y)
(Q : nat -> A -> ★) (h1 : cond1 Q) (h2 : cond2 Q) => (Q : nat → A → ★) (h1 : cond1 Q) (h2 : cond2 Q) =>
h2 n y (h Q h1 h2); h2 n y (h Q h1 h2);
def rec_rel_total : total nat A rec_rel := def rec_rel_total : total nat A rec_rel :=
@ -215,7 +215,7 @@ def rec_rel_alt (x : nat) (y : A) := alt_cond1 x y alt_cond2 x y;
-- {{{ R = R2 -- {{{ R = R2
-- {{{ R2 ⊆ R -- {{{ R2 ⊆ R
def R2_sub_R_case1 (x : nat) (y : A) : alt_cond1 x y -> rec_rel x y := def R2_sub_R_case1 (x : nat) (y : A) : alt_cond1 x y rec_rel x y :=
fun (case1 : alt_cond1 x y) => fun (case1 : alt_cond1 x y) =>
let (x0 := and_elim_l (x = zero) (eq A y z) case1) let (x0 := and_elim_l (x = zero) (eq A y z) case1)
(yz := and_elim_r (x = zero) (eq A y z) case1) (yz := and_elim_r (x = zero) (eq A y z) case1)
@ -224,7 +224,7 @@ def R2_sub_R_case1 (x : nat) (y : A) : alt_cond1 x y -> rec_rel x y :=
(eq_sym nat x zero x0) (fun (n : nat) => rec_rel n y) a1 (eq_sym nat x zero x0) (fun (n : nat) => rec_rel n y) a1
end; end;
def R2_sub_R_case2 (x : nat) (y : A) : alt_cond2 x y -> rec_rel x y := def R2_sub_R_case2 (x : nat) (y : A) : alt_cond2 x y rec_rel x y :=
fun (case2 : alt_cond2 x y) => fun (case2 : alt_cond2 x y) =>
let (h1 := cond_x2 x y) let (h1 := cond_x2 x y)
(h2 := cond_y2 x y) (h2 := cond_y2 x y)
@ -246,7 +246,7 @@ def R2_sub_R_case2 (x : nat) (y : A) : alt_cond2 x y -> rec_rel x y :=
end) end)
end; end;
def R2_sub_R (x : nat) (y : A) : rec_rel_alt x y -> rec_rel x y := def R2_sub_R (x : nat) (y : A) : rec_rel_alt x y rec_rel x y :=
fun (h : rec_rel_alt x y) => fun (h : rec_rel_alt x y) =>
or_elim (alt_cond1 x y) (alt_cond2 x y) (rec_rel x y) h or_elim (alt_cond1 x y) (alt_cond2 x y) (rec_rel x y) h
(R2_sub_R_case1 x y) (R2_sub_R_case1 x y)
@ -278,7 +278,7 @@ def R2_cond2 : cond2 rec_rel_alt :=
end; end;
def R_sub_R2 (x : nat) (y : A) : rec_rel x y -> rec_rel_alt x y := def R_sub_R2 (x : nat) (y : A) : rec_rel x y rec_rel_alt x y :=
fun (h : rec_rel x y) => h rec_rel_alt R2_cond1 R2_cond2; fun (h : rec_rel x y) => h rec_rel_alt R2_cond1 R2_cond2;
-- }}} -- }}}
@ -286,12 +286,12 @@ def R_sub_R2 (x : nat) (y : A) : rec_rel x y -> rec_rel_alt x y :=
-- {{{ R2 (hence R) is functional -- {{{ R2 (hence R) is functional
def fl_in (A B : ★) (R : A -> B -> ★) (x : A) := forall (y1 y2 : B), def fl_in (A B : ★) (R : A → B → ★) (x : A) := forall (y1 y2 : B),
R x y1 -> R x y2 -> eq B y1 y2; R x y1 → R x y2 → eq B y1 y2;
def fl (A B : ★) (R : A -> B -> ★) := forall (x : A), fl_in A B R x; def fl (A B : ★) (R : A → B → ★) := forall (x : A), fl_in A B R x;
def R2_zero (y : A) : rec_rel_alt zero y -> eq A y z := def R2_zero (y : A) : rec_rel_alt zero y eq A y z :=
let (cx2 := cond_x2 zero y) let (cx2 := cond_x2 zero y)
(cy2 := cond_y2 zero y) (cy2 := cond_y2 zero y)
in fun (h : rec_rel_alt zero y) => in fun (h : rec_rel_alt zero y) =>
@ -305,7 +305,7 @@ def R2_zero (y : A) : rec_rel_alt zero y -> eq A y z :=
(eq A y z))) (eq A y z)))
end; end;
def R2_suc (x2 : nat) (y : A) : rec_rel_alt (suc x2) y -> exists A (cond_y2 (suc x2) y x2) := def R2_suc (x2 : nat) (y : A) : rec_rel_alt (suc x2) y exists A (cond_y2 (suc x2) y x2) :=
let (x := suc x2) let (x := suc x2)
(cx2 := cond_x2 x y) (cx2 := cond_x2 x y)
(cy2 := cond_y2 x y) (cy2 := cond_y2 x y)
@ -386,21 +386,21 @@ def rec_def (x : nat) : A :=
-- existential, it still satisfies the property it definitionally is supposed -- existential, it still satisfies the property it definitionally is supposed
-- to satisfy. This annoying problem would be subverted with proper Σ-types, -- to satisfy. This annoying problem would be subverted with proper Σ-types,
-- provided they had η-equality. -- provided they had η-equality.
axiom definite_description (A : ★) (P : A -> ★) (h : exists A P) : axiom definite_description (A : ★) (P : A ★) (h : exists A P) :
P (exists_elim A A P h (fun (x : A) (_ : P x) => x)); P (exists_elim A A P h (fun (x : A) (_ : P x) => x));
-- Now we can use this axiom to prove that R n (rec_def n). -- Now we can use this axiom to prove that R n (rec_def n).
def rec_def_sat (x : nat) : rec_rel x (rec_def x) := def rec_def_sat (x : nat) : rec_rel x (rec_def x) :=
definite_description A (rec_rel x) (rec_rel_total x); definite_description A (rec_rel x) (rec_rel_total x);
def eq1 (f : nat -> A) := eq A (f zero) z; def eq1 (f : nat A) := eq A (f zero) z;
def eq2 (f : nat -> A) := forall (n : nat), eq A (f (suc n)) (fS n (f n)); def eq2 (f : nat A) := forall (n : nat), eq A (f (suc n)) (fS n (f n));
-- f zero = z -- f zero = z
def rec_def_sat_zero : eq1 rec_def := R_functional zero (rec_def zero) z (rec_def_sat zero) rec_rel_cond1; def rec_def_sat_zero : eq1 rec_def := R_functional zero (rec_def zero) z (rec_def_sat zero) rec_rel_cond1;
-- f n = y -> f (suc n) = fS n y -- f n = y f (suc n) = fS n y
def rec_def_sat_suc : eq2 rec_def := fun (n : nat) => def rec_def_sat_suc : eq2 rec_def := fun (n : nat) =>
R_functional (suc n) (rec_def (suc n)) (fS n (rec_def n)) (rec_def_sat (suc n)) (rec_rel_cond2 n (rec_def n) (rec_def_sat n)); R_functional (suc n) (rec_def (suc n)) (fS n (rec_def n)) (rec_def_sat (suc n)) (rec_rel_cond2 n (rec_def n) (rec_def_sat n));
@ -408,7 +408,7 @@ def rec_def_sat_suc : eq2 rec_def := fun (n : nat) =>
-- {{{ The function satisfying these equations is unique -- {{{ The function satisfying these equations is unique
def rec_def_unique (f g : nat -> A) (h1f : eq1 f) (h2f : eq2 f) (h1g : eq1 g) (h2g : eq2 g) def rec_def_unique (f g : nat A) (h1f : eq1 f) (h2f : eq2 f) (h1g : eq1 g) (h2g : eq2 g)
: forall (n : nat), eq A (f n) (g n) := : forall (n : nat), eq A (f n) (g n) :=
nat_ind (fun (n : nat) => eq A (f n) (g n)) nat_ind (fun (n : nat) => eq A (f n) (g n))
-- base case: f 0 = g 0 -- base case: f 0 = g 0
@ -442,7 +442,7 @@ end RecursiveDefs
def psuc (_ r : nat) := suc r; def psuc (_ r : nat) := suc r;
-- And here's plus! -- And here's plus!
def plus (n : nat) : nat -> nat := rec_def nat n psuc; def plus (n : nat) : nat nat := rec_def nat n psuc;
-- And here's an infix version of it -- And here's an infix version of it
def + (n m : nat) : nat := plus n m; def + (n m : nat) : nat := plus n m;

View file

@ -52,18 +52,6 @@ envLookupVal n = asks ((_val <$>) . M.lookup n) >>= maybe (throwError $ UnboundV
envLookupTy :: Text -> ReaderT Env Result Expr envLookupTy :: Text -> ReaderT Env Result Expr
envLookupTy n = asks ((_ty <$>) . M.lookup n) >>= maybe (throwError $ UnboundVariable n) pure envLookupTy n = asks ((_ty <$>) . M.lookup n) >>= maybe (throwError $ UnboundVariable n) pure
-- reduce until β reducts or let simplifications are impossible in head position
whnf :: Expr -> ReaderT Env Result Expr
whnf (App (Abs _ _ _ v) n) = whnf $ subst 0 n v
whnf (App m n) = do
m' <- whnf m
if m == m'
then pure $ App m n
else whnf $ App m' n
whnf (Free n) = envLookupVal n >>= whnf
whnf (Let _ _ v b) = whnf $ subst 0 v b
whnf e = pure e
reduce :: Expr -> ReaderT Env Result Expr reduce :: Expr -> ReaderT Env Result Expr
reduce (App (Abs _ _ _ v) n) = pure $ subst 0 n v reduce (App (Abs _ _ _ v) n) = pure $ subst 0 n v
reduce (App m n) = App <$> reduce m <*> reduce n reduce (App m n) = App <$> reduce m <*> reduce n
@ -80,6 +68,18 @@ normalize e = do
then pure e then pure e
else normalize e' else normalize e'
-- reduce until β reducts or let simplifications are impossible in head position
whnf :: Expr -> ReaderT Env Result Expr
whnf (App (Abs _ _ _ v) n) = whnf $ subst 0 n v
whnf (App m n) = do
m' <- whnf m
if m == m'
then pure $ App m n
else whnf $ App m' n
whnf (Free n) = envLookupVal n >>= whnf
whnf (Let _ _ v b) = whnf $ subst 0 v b
whnf e = pure e
betaEquiv :: Expr -> Expr -> ReaderT Env Result Bool betaEquiv :: Expr -> Expr -> ReaderT Env Result Bool
betaEquiv e1 e2 betaEquiv e1 e2
| e1 == e2 = pure True | e1 == e2 = pure True

View file

@ -10,7 +10,7 @@ import qualified Data.Text as T
import Errors (Error (..)) import Errors (Error (..))
import IR import IR
import Preprocessor import Preprocessor
import Text.Megaparsec (MonadParsec (..), ParsecT, ShowErrorComponent (..), between, choice, errorBundlePretty, label, runParserT, try) import Text.Megaparsec (MonadParsec (..), ParsecT, ShowErrorComponent (..), choice, errorBundlePretty, label, runParserT, try, between)
import Text.Megaparsec.Char import Text.Megaparsec.Char
import qualified Text.Megaparsec.Char.Lexer as L import qualified Text.Megaparsec.Char.Lexer as L
@ -39,6 +39,9 @@ skipSpace =
lexeme :: Parser a -> Parser a lexeme :: Parser a -> Parser a
lexeme = L.lexeme skipSpace lexeme = L.lexeme skipSpace
parens :: Parser a -> Parser a
parens = between (char '(') (char ')')
symbol :: Text -> Parser () symbol :: Text -> Parser ()
symbol = void . L.symbol skipSpace symbol = void . L.symbol skipSpace
@ -64,7 +67,7 @@ pVar :: Parser IRExpr
pVar = label "variable" $ lexeme $ Var <$> pIdentifier pVar = label "variable" $ lexeme $ Var <$> pIdentifier
pParamGroup :: Parser Text -> Parser [Param] pParamGroup :: Parser Text -> Parser [Param]
pParamGroup ident = lexeme $ label "parameter group" $ between (char '(') (char ')') $ do pParamGroup ident = lexeme $ label "parameter group" $ parens $ do
idents <- some ident idents <- some ident
symbol ":" symbol ":"
ty <- pIRExpr ty <- pIRExpr
@ -157,8 +160,11 @@ pSquare = lexeme $ (symbol "□" <|> symbol "[]") >> option (Level 0) (Level <$>
pSort :: Parser IRExpr pSort :: Parser IRExpr
pSort = lexeme $ pStar <|> pSquare pSort = lexeme $ pStar <|> pSquare
pOpSection :: Parser IRExpr
pOpSection = lexeme $ parens $ Var <$> pSymbol
pTerm :: Parser IRExpr pTerm :: Parser IRExpr
pTerm = lexeme $ label "term" $ choice [pSort, pVar, between (char '(') (char ')') pIRExpr] pTerm = lexeme $ label "term" $ choice [pSort, pVar, try pOpSection, parens pIRExpr]
pInfix :: Parser IRExpr pInfix :: Parser IRExpr
pInfix = parseWithPrec 0 pInfix = parseWithPrec 0