Compare commits

..

No commits in common. "a72fef7979b0a80cae0a9912ee21e2defafaa0b5" and "a3d72583b446366c9d4417f42f1b4067c967a15f" have entirely different histories.

10 changed files with 225 additions and 417 deletions

View file

@ -6,7 +6,6 @@
* Syntax * Syntax
The syntax is fairly flexible and should work as you expect. Identifiers can be Unicode as long as =megaparsec= calls them alphanumeric. =λ= and =Π= abstractions can be written in the usual ways that should be clear from the examples below. Additionally, arrows can be used as an abbreviation for a Π type where the parameter doesn't appear in the body as usual. The syntax is fairly flexible and should work as you expect. Identifiers can be Unicode as long as =megaparsec= calls them alphanumeric. =λ= and =Π= abstractions can be written in the usual ways that should be clear from the examples below. Additionally, arrows can be used as an abbreviation for a Π type where the parameter doesn't appear in the body as usual.
** Terms
All of the following example terms correctly parse, and should look familiar if you are used to standard lambda calculus notation or Coq syntax. All of the following example terms correctly parse, and should look familiar if you are used to standard lambda calculus notation or Coq syntax.
#+begin_src #+begin_src
λ (α : *) ⇒ λ (β : *) ⇒ λ (x : α) ⇒ λ (y : β) ⇒ x λ (α : *) ⇒ λ (β : *) ⇒ λ (x : α) ⇒ λ (y : β) ⇒ x
@ -41,7 +40,6 @@ You can also directly bind functions. Here's an example.
#+end_src #+end_src
The syntax for binding functions is just like with definitions. The syntax for binding functions is just like with definitions.
** Definitions and Axioms
Definitions and axioms have abstract syntax as shown below. Definitions and axioms have abstract syntax as shown below.
#+begin_src #+begin_src
def <ident> (<ident> : <type>)* : <type>? := <term>; def <ident> (<ident> : <type>)* : <type>? := <term>;
@ -59,24 +57,6 @@ Type ascriptions are optional in both definitions and =let= bindings. If include
If the RHS of a definition is =axiom=, then =perga= will assume that the identifier is an inhabitant of the type ascribed to it (as such when using axioms, a type ascription is required). This allows you to use axioms. If the RHS of a definition is =axiom=, then =perga= will assume that the identifier is an inhabitant of the type ascribed to it (as such when using axioms, a type ascription is required). This allows you to use axioms.
** Sections
There is a Coq-like section mechanism. You open a section with =section <identifier>= and close it with =end <identifier>=. The identifiers used must match. The identifiers don't serve any purpose beyond organization.
#+begin_src
section Test
variable (A B : *);
def id (x : A) := x;
def const (x : A) (y : B) := id x;
end Test
def id_full (A : *) (x : A) := id A x;
def const_full (A B : *) (x : A) (y : B) := const A B x y;
#+end_src
In a section, you can add section variables to the context with either =variable= or =hypothesis=. The syntax is the same as function parameters, so you can define multiple variables in one line, and can group section variables of the same type. Then, in the section, any definition using the section variables will be automatically generalized over the section variables that they use. Furthermore, any usage of such section variables (like =id x= in the definition of =const= above) will automatically apply the necessary section variables.
Nested sections are supported, and work as you would expect.
** Comments and preprocessor directives
Line comments are =--= like in Haskell, and block comments are =[* *]= somewhat like ML (and nest properly). There is no significant whitespace, so you are free to format code as you wish. Line comments are =--= like in Haskell, and block comments are =[* *]= somewhat like ML (and nest properly). There is no significant whitespace, so you are free to format code as you wish.
There isn't a proper module system (yet), but you can include other files in a dumb, C preprocessor way by using =@include <filepath>= (NOTE: this unfortunately messes up line numbers in error messages). Filepaths are relative to the current file. Additionally, =@include= automatically keeps track of what has been included, so duplicate inclusions are skipped, meaning no include guards are necessary. There isn't a proper module system (yet), but you can include other files in a dumb, C preprocessor way by using =@include <filepath>= (NOTE: this unfortunately messes up line numbers in error messages). Filepaths are relative to the current file. Additionally, =@include= automatically keeps track of what has been included, so duplicate inclusions are skipped, meaning no include guards are necessary.

View file

@ -23,7 +23,6 @@ data ReplCommand
| WeakNormalize String | WeakNormalize String
| Input String | Input String
| LoadFile String | LoadFile String
| DumpDebug String
deriving (Show) deriving (Show)
parseCommand :: Maybe String -> Maybe ReplCommand parseCommand :: Maybe String -> Maybe ReplCommand
@ -36,7 +35,6 @@ parseCommand (Just input)
| ":n " `isPrefixOf` input = Normalize <$> stripPrefix ":n " input | ":n " `isPrefixOf` input = Normalize <$> stripPrefix ":n " input
| ":w " `isPrefixOf` input = WeakNormalize <$> stripPrefix ":w " input | ":w " `isPrefixOf` input = WeakNormalize <$> stripPrefix ":w " input
| ":l " `isPrefixOf` input = LoadFile <$> stripPrefix ":l " input | ":l " `isPrefixOf` input = LoadFile <$> stripPrefix ":l " input
| ":d " `isPrefixOf` input = DumpDebug <$> stripPrefix ":d " input
| otherwise = Just $ Input input | otherwise = Just $ Input input
handleInput :: Env -> String -> InputT IO Env handleInput :: Env -> String -> InputT IO Env
@ -48,7 +46,9 @@ handleInput env input =
Right env' -> pure env' Right env' -> pure env'
actOnParse :: String -> (Expr -> InputT IO ()) -> InputT IO () actOnParse :: String -> (Expr -> InputT IO ()) -> InputT IO ()
actOnParse input action = either outputStrLn (action . elaborate) $ parseExpr "repl" (pack input) actOnParse input action = case parseExpr "repl" (pack input) of
Left err -> outputStrLn err
Right expr -> action $ elaborate expr
printErrorOrResult :: Env -> (Expr -> ReaderT Env Result Expr) -> Expr -> InputT IO () printErrorOrResult :: Env -> (Expr -> ReaderT Env Result Expr) -> Expr -> InputT IO ()
printErrorOrResult env action expr = putTextLn $ either toText pretty $ runReaderT (action expr) env printErrorOrResult env action expr = putTextLn $ either toText pretty $ runReaderT (action expr) env
@ -78,6 +78,5 @@ repl = do
Just (ValueQuery input) -> lookupAct env input (putTextLn . pretty . _val) >> loop env Just (ValueQuery input) -> lookupAct env input (putTextLn . pretty . _val) >> loop env
Just (Normalize input) -> parseActPrint env input normalize >> loop env Just (Normalize input) -> parseActPrint env input normalize >> loop env
Just (WeakNormalize input) -> parseActPrint env input whnf >> loop env Just (WeakNormalize input) -> parseActPrint env input whnf >> loop env
Just (DumpDebug input) -> either outputStrLn (outputStrLn . show) (parseDef "repl" (pack input)) >> loop env
Just (LoadFile filename) -> lift (runExceptT $ handleAndParseFile env filename) >>= either ((>> loop env) . outputStrLn) loop Just (LoadFile filename) -> lift (runExceptT $ handleAndParseFile env filename) >>= either ((>> loop env) . outputStrLn) loop
Just (Input input) -> handleInput env input >>= loop Just (Input input) -> handleInput env input >>= loop

View file

@ -115,25 +115,21 @@ def eq_cong (A B : *) (x y : A) (f : A -> B) (H : eq A x y) : eq B (f x) (f y) :
-- Some logic theorems -- Some logic theorems
section Theorems
variable (A B C : *);
-- ~(A B) => ~A ∧ ~B -- ~(A B) => ~A ∧ ~B
def de_morgan1 (h : not (or A B)) : and (not A) (not B) := def de_morgan1 (A B : *) (h : not (or A B)) : and (not A) (not B) :=
and_intro (not A) (not B) and_intro (not A) (not B)
(fun (a : A) => h (or_intro_l A B a)) (fun (a : A) => h (or_intro_l A B a))
(fun (b : B) => h (or_intro_r A B b)); (fun (b : B) => h (or_intro_r A B b));
-- ~A ∧ ~B => ~(A B) -- ~A ∧ ~B => ~(A B)
def de_morgan2 (h : and (not A) (not B)) : not (or A B) := def de_morgan2 (A B : *) (h : and (not A) (not B)) : not (or A B) :=
fun (contra : or A B) => fun (contra : or A B) =>
or_elim A B false contra or_elim A B false contra
(and_elim_l (not A) (not B) h) (and_elim_l (not A) (not B) h)
(and_elim_r (not A) (not B) h); (and_elim_r (not A) (not B) h);
-- ~A ~B => ~(A ∧ B) -- ~A ~B => ~(A ∧ B)
def de_morgan3 (h : or (not A) (not B)) : not (and A B) := def de_morgan3 (A B : *) (h : or (not A) (not B)) : not (and A B) :=
fun (contra : and A B) => fun (contra : and A B) =>
or_elim (not A) (not B) false h or_elim (not A) (not B) false h
(fun (na : not A) => na (and_elim_l A B contra)) (fun (na : not A) => na (and_elim_l A B contra))
@ -142,19 +138,19 @@ section Theorems
-- the last one (~(A ∧ B) => ~A ~B) is not possible constructively -- the last one (~(A ∧ B) => ~A ~B) is not possible constructively
-- A ∧ B => B ∧ A -- A ∧ B => B ∧ A
def and_comm (h : and A B) : and B A := def and_comm (A B : *) (h : and A B) : and B A :=
and_intro B A and_intro B A
(and_elim_r A B h) (and_elim_r A B h)
(and_elim_l A B h); (and_elim_l A B h);
-- A B => B A -- A B => B A
def or_comm (h : or A B) : or B A := def or_comm (A B : *) (h : or A B) : or B A :=
or_elim A B (or B A) h or_elim A B (or B A) h
(fun (a : A) => or_intro_r B A a) (fun (a : A) => or_intro_r B A a)
(fun (b : B) => or_intro_l B A b); (fun (b : B) => or_intro_l B A b);
-- A ∧ (B ∧ C) => (A ∧ B) ∧ C -- A ∧ (B ∧ C) => (A ∧ B) ∧ C
def and_assoc_l (h : and A (and B C)) : and (and A B) C := def and_assoc_l (A B C : *) (h : and A (and B C)) : and (and A B) C :=
let (a := (and_elim_l A (and B C) h)) let (a := (and_elim_l A (and B C) h))
(bc := (and_elim_r A (and B C) h)) (bc := (and_elim_r A (and B C) h))
(b := (and_elim_l B C bc)) (b := (and_elim_l B C bc))
@ -164,7 +160,7 @@ section Theorems
end; end;
-- (A ∧ B) ∧ C => A ∧ (B ∧ C) -- (A ∧ B) ∧ C => A ∧ (B ∧ C)
def and_assoc_r (h : and (and A B) C) : and A (and B C) := def and_assoc_r (A B C : *) (h : and (and A B) C) : and A (and B C) :=
let (ab := and_elim_l (and A B) C h) let (ab := and_elim_l (and A B) C h)
(a := and_elim_l A B ab) (a := and_elim_l A B ab)
(b := and_elim_r A B ab) (b := and_elim_r A B ab)
@ -174,7 +170,7 @@ section Theorems
end; end;
-- A (B C) => (A B) C -- A (B C) => (A B) C
def or_assoc_l (h : or A (or B C)) : or (or A B) C := def or_assoc_l (A B C : *) (h : or A (or B C)) : or (or A B) C :=
or_elim A (or B C) (or (or A B) C) h or_elim A (or B C) (or (or A B) C) h
(fun (a : A) => or_intro_l (or A B) C (or_intro_l A B a)) (fun (a : A) => or_intro_l (or A B) C (or_intro_l A B a))
(fun (g : or B C) => (fun (g : or B C) =>
@ -183,7 +179,7 @@ section Theorems
(fun (c : C) => or_intro_r (or A B) C c)); (fun (c : C) => or_intro_r (or A B) C c));
-- (A B) C => A (B C) -- (A B) C => A (B C)
def or_assoc_r (h : or (or A B) C) : or A (or B C) := def or_assoc_r (A B C : *) (h : or (or A B) C) : or A (or B C) :=
or_elim (or A B) C (or A (or B C)) h or_elim (or A B) C (or A (or B C)) h
(fun (g : or A B) => (fun (g : or A B) =>
or_elim A B (or A (or B C)) g or_elim A B (or A (or B C)) g
@ -192,7 +188,7 @@ section Theorems
(fun (c : C) => or_intro_r A (or B C) (or_intro_r B C c)); (fun (c : C) => or_intro_r A (or B C) (or_intro_r B C c));
-- A ∧ (B C) => A ∧ B A ∧ C -- A ∧ (B C) => A ∧ B A ∧ C
def and_distrib_l_or (h : and A (or B C)) : or (and A B) (and A C) := def and_distrib_l_or (A B C : *) (h : and A (or B C)) : or (and A B) (and A C) :=
or_elim B C (or (and A B) (and A C)) (and_elim_r A (or B C) h) or_elim B C (or (and A B) (and A C)) (and_elim_r A (or B C) h)
(fun (b : B) => or_intro_l (and A B) (and A C) (fun (b : B) => or_intro_l (and A B) (and A C)
(and_intro A B (and_elim_l A (or B C) h) b)) (and_intro A B (and_elim_l A (or B C) h) b))
@ -200,7 +196,7 @@ section Theorems
(and_intro A C (and_elim_l A (or B C) h) c)); (and_intro A C (and_elim_l A (or B C) h) c));
-- A ∧ B A ∧ C => A ∧ (B C) -- A ∧ B A ∧ C => A ∧ (B C)
def and_factor_l_or (h : or (and A B) (and A C)) : and A (or B C) := def and_factor_l_or (A B C : *) (h : or (and A B) (and A C)) : and A (or B C) :=
or_elim (and A B) (and A C) (and A (or B C)) h or_elim (and A B) (and A C) (and A (or B C)) h
(fun (ab : and A B) => and_intro A (or B C) (fun (ab : and A B) => and_intro A (or B C)
(and_elim_l A B ab) (and_elim_l A B ab)
@ -211,11 +207,9 @@ section Theorems
-- Thanks Quinn! -- Thanks Quinn!
-- A B => ~B => A -- A B => ~B => A
def disj_syllog (nb : not B) (hor : or A B) : A := def disj_syllog (A B : *) (nb : not B) (hor : or A B) : A :=
or_elim A B A hor (fun (a : A) => a) (fun (b : B) => nb b A); or_elim A B A hor (fun (a : A) => a) (fun (b : B) => nb b A);
-- (A => B) => ~B => ~A -- (A => B) => ~B => ~A
def contrapositive (f : A -> B) (nb : not B) : not A := def contrapositive (A B : *) (f : A -> B) (nb : not B) : not A :=
fun (a : A) => nb (f a); fun (a : A) => nb (f a);
end Theorems

View file

@ -155,72 +155,73 @@ def suc_or_zero : forall (n : nat), szc n :=
-- 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
-- actually a function satisfying the equations we want it to. -- actually a function satisfying the equations we want it to.
section RecursiveDefs
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 (A : *) (z : A) (fS : nat -> A -> A) (Q : nat -> A -> *) :=
Q zero z;
-- Likewise for condition 2. -- Likewise for condition 2.
def cond2 (Q : nat -> A -> *) := def cond2 (A : *) (z : A) (fS : nat -> A -> A) (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 (A : *) (z : A) (fS : nat -> A -> A) (x : nat) (y : A) :=
forall (Q : nat -> A -> *), cond1 Q -> cond2 Q -> Q x y; forall (Q : nat -> A -> *), cond1 A z fS Q -> cond2 A z fS 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 (A : *) (z : A) (fS : nat -> A -> A) : cond1 A z fS (rec_rel A z fS) :=
fun (Q : nat -> A -> *) (h1 : cond1 Q) (h2 : cond2 Q) => h1; fun (Q : nat -> A -> *) (h1 : cond1 A z fS Q) (h2 : cond2 A z fS Q) => h1;
def rec_rel_cond2 : cond2 rec_rel := def rec_rel_cond2 (A : *) (z : A) (fS : nat -> A -> A) : cond2 A z fS (rec_rel A z fS) :=
fun (n : nat) (y : A) (h : rec_rel n y) fun (n : nat) (y : A) (h : rec_rel A z fS n y)
(Q : nat -> A -> *) (h1 : cond1 Q) (h2 : cond2 Q) => (Q : nat -> A -> *) (h1 : cond1 A z fS Q) (h2 : cond2 A z fS 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 (A : *) (z : A) (fS : nat -> A -> A) : total nat A (rec_rel A z fS) :=
let (R := rec_rel) let (R := rec_rel A z fS)
(P (x : nat) := exists A (R x)) (P (x : nat) := exists A (R x))
(c1 := cond1 A z fS)
(c2 := cond2 A z fS)
in in
nat_ind P nat_ind P
(exists_intro A (R zero) z rec_rel_cond1) (exists_intro A (R zero) z (rec_rel_cond1 A z fS))
(fun (n : nat) (IH : P n) => (fun (n : nat) (IH : P n) =>
exists_elim A (P (suc n)) (R n) IH exists_elim A (P (suc n)) (R n) IH
(fun (y0 : A) (hy : R n y0) => (fun (y0 : A) (hy : R n y0) =>
exists_intro A (R (suc n)) (fS n y0) (rec_rel_cond2 n y0 hy))) exists_intro A (R (suc n)) (fS n y0) (rec_rel_cond2 A z fS n y0 hy)))
end; end;
-- }}} -- }}}
-- {{{ Defining R2 -- {{{ Defining R2
def alt_cond1 (x : nat) (y : A) := def alt_cond1 (A : *) (z : A) (x : nat) (y : A) :=
and (eq nat x zero) (eq A y z); and (eq nat x zero) (eq A y z);
def cond_y2 (x : nat) (y : A) def cond_y2 (A : *) (z : A) (fS : nat -> A -> A) (x : nat) (y : A)
(x2 : nat) (y2 : A) := (x2 : nat) (y2 : A) :=
and (eq A y (fS x2 y2)) (rec_rel x2 y2); and (eq A y (fS x2 y2)) (rec_rel A z fS x2 y2);
def cond_x2 (x : nat) (y : A) (x2 : nat) := def cond_x2 (A : *) (z : A) (fS : nat -> A -> A) (x : nat) (y : A) (x2 : nat) :=
and (pred x x2) (exists A (cond_y2 x y x2)); and (pred x x2) (exists A (cond_y2 A z fS x y x2));
def alt_cond2 (x : nat) (y : A) := exists nat (cond_x2 x y); def alt_cond2 (A : *) (z : A) (fS : nat -> A -> A) (x : nat) (y : A) :=
exists nat (cond_x2 A z fS x y);
def rec_rel_alt (x : nat) (y : A) := or (alt_cond1 x y) (alt_cond2 x y); def rec_rel_alt (A : *) (z : A) (fS : nat -> A -> A) (x : nat) (y : A) :=
or (alt_cond1 A z x y) (alt_cond2 A z fS x y);
-- }}} -- }}}
-- {{{ R = R2 -- {{{ R = R2
-- {{{ R2 ⊆ R -- {{{ R2 ⊆ R
def R2_sub_R (x : nat) (y : A) : rec_rel_alt x y -> rec_rel x y := def R2_sub_R (A : *) (z : A) (fS : nat -> A -> A) (x : nat) (y : A) :
let (R := rec_rel) rec_rel_alt A z fS x y -> rec_rel A z fS x y :=
(R2 := rec_rel_alt) let (R := rec_rel A z fS)
(ac1 := alt_cond1 x y) (R2 := rec_rel_alt A z fS)
(ac2 := alt_cond2 x y) (ac1 := alt_cond1 A z x y)
(ac2 := alt_cond2 A z fS x y)
in in
fun (h : R2 x y) => fun (h : R2 x y) =>
or_elim ac1 ac2 (R x y) h or_elim ac1 ac2 (R x y) h
@ -228,13 +229,13 @@ def R2_sub_R (x : nat) (y : A) : rec_rel_alt x y -> rec_rel x y :=
let let
(x0 := and_elim_l (eq nat x zero) (eq A y z) case1) (x0 := and_elim_l (eq nat x zero) (eq A y z) case1)
(yz := and_elim_r (eq nat x zero) (eq A y z) case1) (yz := and_elim_r (eq nat x zero) (eq A y z) case1)
(a1 := (eq_sym A y z yz) (R zero) rec_rel_cond1) (a1 := (eq_sym A y z yz) (R zero) (rec_rel_cond1 A z fS))
in in
(eq_sym nat x zero x0) (fun (n : nat) => R n y) a1 (eq_sym nat x zero x0) (fun (n : nat) => R n y) a1
end) end)
(fun (case2 : ac2) => (fun (case2 : ac2) =>
let (h1 := cond_x2 x y) let (h1 := cond_x2 A z fS x y)
(h2 := cond_y2 x y) (h2 := cond_y2 A z fS x y)
in in
exists_elim nat (R x y) h1 case2 exists_elim nat (R x y) h1 case2
(fun (x2 : nat) (hx2 : h1 x2) => (fun (x2 : nat) (hx2 : h1 x2) =>
@ -245,7 +246,7 @@ def R2_sub_R (x : nat) (y : A) : rec_rel_alt x y -> rec_rel x y :=
(fun (y2 : A) (hy2 : h2 x2 y2) => (fun (y2 : A) (hy2 : h2 x2 y2) =>
let (hpreim := and_elim_l (eq A y (fS x2 y2)) (R x2 y2) hy2) let (hpreim := and_elim_l (eq A y (fS x2 y2)) (R x2 y2) hy2)
(hR := and_elim_r (eq A y (fS x2 y2)) (R x2 y2) hy2) (hR := and_elim_r (eq A y (fS x2 y2)) (R x2 y2) hy2)
(a1 := rec_rel_cond2 x2 y2 hR) (a1 := rec_rel_cond2 A z fS x2 y2 hR)
(a2 := (eq_sym A y (fS x2 y2) hpreim) (R (suc x2)) a1) (a2 := (eq_sym A y (fS x2 y2) hpreim) (R (suc x2)) a1)
in in
(eq_sym nat x (suc x2) hpred) (fun (n : nat) => R n y) a2 (eq_sym nat x (suc x2) hpred) (fun (n : nat) => R n y) a2
@ -256,36 +257,41 @@ def R2_sub_R (x : nat) (y : A) : rec_rel_alt x y -> rec_rel x y :=
-- }}} -- }}}
-- {{{ R ⊆ R2 -- {{{ R ⊆ R2
def R2_cond1 : cond1 rec_rel_alt := def R2_cond1 (A : *) (z : A) (fS : nat -> A -> A) : cond1 A z fS (rec_rel_alt A z fS) :=
or_intro_l (alt_cond1 zero z) (alt_cond2 zero z) or_intro_l (alt_cond1 A z zero z) (alt_cond2 A z fS zero z)
(and_intro (eq nat zero zero) (eq A z z) (and_intro (eq nat zero zero) (eq A z z)
(eq_refl nat zero) (eq_refl nat zero)
(eq_refl A z)); (eq_refl A z));
def R2_cond2 : cond2 rec_rel_alt := def R2_cond2 (A : *) (z : A) (fS : nat -> A -> A) : cond2 A z fS (rec_rel_alt A z fS) :=
let (R := rec_rel) let (R := rec_rel A z fS)
(R2 := rec_rel_alt) (R2 := rec_rel_alt A z fS)
in in
fun (x2 : nat) (y2 : A) (h : R2 x2 y2) => fun (x2 : nat) (y2 : A) (h : R2 x2 y2) =>
let (x := suc x2) let (x := suc x2)
(y := fS x2 y2) (y := fS x2 y2)
(cx2 := cond_x2 x y) (cx2 := cond_x2 A z fS x y)
(cy2 := cond_y2 x y x2) (cy2 := cond_y2 A z fS x y x2)
in in
or_intro_r (alt_cond1 x y) (alt_cond2 x y) or_intro_r (alt_cond1 A z x y) (alt_cond2 A z fS x y)
(exists_intro nat cx2 x2 (exists_intro nat cx2 x2
(and_intro (pred x x2) (exists A cy2) (and_intro (pred x x2) (exists A cy2)
(eq_refl nat x) (eq_refl nat x)
(exists_intro A cy2 y2 (exists_intro A cy2 y2
(and_intro (eq A y y) (R x2 y2) (and_intro (eq A y y) (R x2 y2)
(eq_refl A y) (eq_refl A y)
(R2_sub_R x2 y2 h))))) (R2_sub_R A z fS x2 y2 h)))))
end end
end; end;
def R_sub_R2 (A : *) (z : A) (fS : nat -> A -> A) (x : nat) (y : A) :
def R_sub_R2 (x : nat) (y : A) : rec_rel x y -> rec_rel_alt x y := rec_rel A z fS x y -> rec_rel_alt A z fS x y :=
fun (h : rec_rel x y) => h rec_rel_alt R2_cond1 R2_cond2; let (R := rec_rel A z fS)
(R2 := rec_rel_alt A z fS)
in
fun (h : R x y) =>
h R2 (R2_cond1 A z fS) (R2_cond2 A z fS)
end;
-- }}} -- }}}
-- }}} -- }}}
@ -297,12 +303,13 @@ def fl_in (A B : *) (R : A -> B -> *) (x : A) := forall (y1 y2 : B),
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 (A : *) (z : A) (fS : nat -> A -> A) (y : A) :
let (R2 := rec_rel_alt) rec_rel_alt A z fS zero y -> eq A y z :=
(ac1 := alt_cond1 zero y) let (R2 := rec_rel_alt A z fS)
(ac2 := alt_cond2 zero y) (ac1 := alt_cond1 A z zero y)
(cx2 := cond_x2 zero y) (ac2 := alt_cond2 A z fS zero y)
(cy2 := cond_y2 zero y) (cx2 := cond_x2 A z fS zero y)
(cy2 := cond_y2 A z fS zero y)
in fun (h : R2 zero y) => in fun (h : R2 zero y) =>
or_elim ac1 ac2 (eq A y z) h or_elim ac1 ac2 (eq A y z) h
(fun (case1 : ac1) => and_elim_r (eq nat zero zero) (eq A y z) case1) (fun (case1 : ac1) => and_elim_r (eq nat zero zero) (eq A y z) case1)
@ -314,13 +321,14 @@ 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 (A : *) (z : A) (fS : nat -> A -> A) (x2 : nat) (y : A) :
let (R2 := rec_rel_alt) rec_rel_alt A z fS (suc x2) y -> exists A (cond_y2 A z fS (suc x2) y x2) :=
let (R2 := rec_rel_alt A z fS)
(x := suc x2) (x := suc x2)
(ac1 := alt_cond1 x y) (ac1 := alt_cond1 A z x y)
(ac2 := alt_cond2 x y) (ac2 := alt_cond2 A z fS x y)
(cx2 := cond_x2 x y) (cx2 := cond_x2 A z fS x y)
(cy2 := cond_y2 x y) (cy2 := cond_y2 A z fS x y)
(goal := exists A (cy2 x2)) (goal := exists A (cy2 x2))
in in
fun (h : R2 x y) => fun (h : R2 x y) =>
@ -339,31 +347,31 @@ def R2_suc (x2 : nat) (y : A) : rec_rel_alt (suc x2) y -> exists A (cond_y2 (suc
end)) end))
end; end;
def R2_functional : fl nat A rec_rel_alt := def R2_functional (A : *) (z : A) (fS : nat -> A -> A) : fl nat A (rec_rel_alt A z fS) :=
let (R := rec_rel) let (R := rec_rel A z fS)
(R2 := rec_rel_alt) (R2 := rec_rel_alt A z fS)
(f_in := fl_in nat A R2) (f_in := fl_in nat A R2)
in nat_ind f_in in nat_ind f_in
(fun (y1 y2 : A) (h1 : R2 zero y1) (h2 : R2 zero y2) => (fun (y1 y2 : A) (h1 : R2 zero y1) (h2 : R2 zero y2) =>
eq_trans A y1 z y2 eq_trans A y1 z y2
(R2_zero y1 h1) (R2_zero A z fS y1 h1)
(eq_sym A y2 z (R2_zero y2 h2))) (eq_sym A y2 z (R2_zero A z fS y2 h2)))
(fun (x2 : nat) (IH : f_in x2) (y1 y2 : A) (h1 : R2 (suc x2) y1) (h2 : R2 (suc x2) y2) => (fun (x2 : nat) (IH : f_in x2) (y1 y2 : A) (h1 : R2 (suc x2) y1) (h2 : R2 (suc x2) y2) =>
let (x := suc x2) let (x := suc x2)
(cy1 := cond_y2 x y1 x2) (cy1 := cond_y2 A z fS x y1 x2)
(cy2 := cond_y2 x y2 x2) (cy2 := cond_y2 A z fS x y2 x2)
(goal := eq A y1 y2) (goal := eq A y1 y2)
in in
exists_elim A goal cy1 (R2_suc x2 y1 h1) exists_elim A goal cy1 (R2_suc A z fS x2 y1 h1)
(fun (y12 : A) (h12 : cy1 y12) => (fun (y12 : A) (h12 : cy1 y12) =>
exists_elim A goal cy2 (R2_suc x2 y2 h2) exists_elim A goal cy2 (R2_suc A z fS x2 y2 h2)
(fun (y22 : A) (h22 : cy2 y22) => (fun (y22 : A) (h22 : cy2 y22) =>
let (y1_preim := and_elim_l (eq A y1 (fS x2 y12)) (R x2 y12) h12) let (y1_preim := and_elim_l (eq A y1 (fS x2 y12)) (R x2 y12) h12)
(y2_preim := and_elim_l (eq A y2 (fS x2 y22)) (R x2 y22) h22) (y2_preim := and_elim_l (eq A y2 (fS x2 y22)) (R x2 y22) h22)
(R_x2_y12 := and_elim_r (eq A y1 (fS x2 y12)) (R x2 y12) h12) (R_x2_y12 := and_elim_r (eq A y1 (fS x2 y12)) (R x2 y12) h12)
(R_x2_y22 := and_elim_r (eq A y2 (fS x2 y22)) (R x2 y22) h22) (R_x2_y22 := and_elim_r (eq A y2 (fS x2 y22)) (R x2 y22) h22)
(R2_x2_y12 := R_sub_R2 x2 y12 R_x2_y12) (R2_x2_y12 := R_sub_R2 A z fS x2 y12 R_x2_y12)
(R2_x2_y22 := R_sub_R2 x2 y22 R_x2_y22) (R2_x2_y22 := R_sub_R2 A z fS x2 y22 R_x2_y22)
(y12_y22 := IH y12 y22 R2_x2_y12 R2_x2_y22) (y12_y22 := IH y12 y22 R2_x2_y12 R2_x2_y22)
in in
eq_trans A y1 (fS x2 y12) y2 eq_trans A y1 (fS x2 y12) y2
@ -375,16 +383,21 @@ def R2_functional : fl nat A rec_rel_alt :=
end) end)
end; end;
def R_functional : fl nat A rec_rel := def R_functional (A : *) (z : A) (fS : nat -> A -> A) : fl nat A (rec_rel A z fS) :=
fun (n : nat) (y1 y2 : A) (h1 : rec_rel n y1) (h2 : rec_rel n y2) => let (R := rec_rel A z fS)
R2_functional n y1 y2 (R_sub_R2 n y1 h1) (R_sub_R2 n y2 h2); (sub := R_sub_R2 A z fS)
in
fun (n : nat) (y1 y2 : A) (h1 : R n y1) (h2 : R n y2) =>
R2_functional A z fS n y1 y2 (sub n y1 h1) (sub n y2 h2)
end;
-- }}} -- }}}
-- {{{ Actually defining the function -- {{{ Actually defining the function
def rec_def (x : nat) : A := def rec_def (A : *) (z : A) (fS : nat -> A -> A) (x : nat) : A :=
exists_elim A A (rec_rel x) (rec_rel_total x) (fun (y : A) (_ : rec_rel x y) => y); exists_elim A A (rec_rel A z fS x) (rec_rel_total A z fS x)
(fun (y : A) (_ : rec_rel A z fS x y) => y);
-- }}} -- }}}
@ -402,30 +415,39 @@ 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 (A : *) (z : A) (fS : nat -> A -> A) (x : nat) : rec_rel A z fS x (rec_def A z fS x) :=
definite_description A (rec_rel x) (rec_rel_total x); definite_description A (rec_rel A z fS x) (rec_rel_total A z fS x);
def eq1 (f : nat -> A) := eq A (f zero) z; def eq1 (A : *) (z : A) (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 (A : *) (z : A) (fS : nat -> A -> A) (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 (A : *) (z : A) (fS : nat -> A -> A) : eq1 A z (rec_def A z fS) :=
let (f := rec_def A z fS) in
R_functional A z fS zero (f zero) z
(rec_def_sat A z fS zero)
(rec_rel_cond1 A z fS)
end;
-- 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 := def rec_def_sat_suc (A : *) (z : A) (fS : nat -> A -> A) : eq2 A z fS (rec_def A z fS) :=
fun (n : nat) => fun (n : nat) =>
let (y := rec_def n) let (R := rec_rel A z fS)
(RSnfy := rec_rel_cond2 n y (rec_def_sat n)) (f := rec_def A z fS)
(y := f n)
(Rf := rec_def_sat A z fS)
(RSnfy := rec_rel_cond2 A z fS n y (Rf n))
in in
R_functional (suc n) (rec_def (suc n)) (fS n y) (rec_def_sat (suc n)) RSnfy R_functional A z fS (suc n) (f (suc n)) (fS n y) (Rf (suc n)) RSnfy
end; end;
-- }}} -- }}}
-- {{{ The function satisfying these equations is unique -- {{{ The function satisfying these equations is unique
def rec_def_unique (fS : nat -> A -> A) (f g : nat -> A) (h1f : eq1 f) (h2f : eq2 f) (h1g : eq1 g) (h2g : eq2 g) def rec_def_unique (A : *) (z : A) (fS : nat -> A -> A) (f g : nat -> A)
(h1f : eq1 A z f) (h2f : eq2 A z fS f) (h1g : eq1 A z g) (h2g : eq2 A z fS 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
@ -448,8 +470,6 @@ def rec_def_unique (fS : nat -> A -> A) (f g : nat -> A) (h1f : eq1 f) (h2f : eq
-- }}} -- }}}
end RecursiveDefs
-- }}} -- }}}
-- Now we can safely define addition. -- Now we can safely define addition.

View file

@ -1,174 +1,13 @@
{-# LANGUAGE TupleSections #-}
module Elaborator where module Elaborator where
import Data.List (elemIndex, lookup) import Data.List (elemIndex)
import qualified Data.Set as S
import Expr (Expr) import Expr (Expr)
import qualified Expr as E import qualified Expr as E
import IR (IRDef (..), IRExpr, IRProgram, IRSectionDef (..)) import IR (IRExpr)
import qualified IR as I import qualified IR as I
import Relude.Extra.Lens
type Binders = [Text] type Binders = [Text]
data SectionContext = SectionContext
{ sectionDefs :: [(Text, [(Text, IRExpr)])] -- name and list of variables and their types it depends on
, sectionVars :: [(Text, IRExpr)] -- variables and their types
}
type ElabMonad = State SectionContext
lookupDefInCtxt :: Text -> SectionContext -> Maybe [(Text, IRExpr)]
lookupDefInCtxt def (SectionContext defs _) = lookup def defs
-- looks up a definition in the context and gives a list of the variables and
-- their types that it depends on
lookupDef :: Text -> ElabMonad (Maybe [(Text, IRExpr)])
lookupDef def = lookupDefInCtxt def <$> get
lookupVarInCtxt :: Text -> SectionContext -> Maybe IRExpr
lookupVarInCtxt var = lookup var . sectionVars
-- looks up a variable in the context and returns its type
lookupVar :: Text -> ElabMonad (Maybe IRExpr)
lookupVar var = lookupVarInCtxt var <$> get
sectionDefsL :: Lens' SectionContext [(Text, [(Text, IRExpr)])]
sectionDefsL = lens sectionDefs setter
where
setter ctxt newDefs = ctxt{sectionDefs = newDefs}
sectionVarsL :: Lens' SectionContext [(Text, IRExpr)]
sectionVarsL = lens sectionVars setter
where
setter ctxt newVars = ctxt{sectionVars = newVars}
saveState :: ElabMonad a -> ElabMonad a
saveState action = get >>= (action <*) . put
debugIRExpr :: IRExpr -> String
debugIRExpr = E.prettyS . elaborate
debugIRDef :: IRDef -> String
debugIRDef (Def name (Just ty) body) = "def " ++ toString name ++ " : " ++ debugIRExpr ty ++ " := " ++ debugIRExpr body ++ ";"
debugIRDef (Def name Nothing body) = "def " ++ toString name ++ " := " ++ debugIRExpr body ++ ";"
debugIRDef (Axiom name typ) = "axiom " ++ toString name ++ " : " ++ debugIRExpr typ ++ ";"
debugIRSectionDef :: IRSectionDef -> String
debugIRSectionDef (Variable name typ) = "variable " ++ toString name ++ " : " ++ debugIRExpr typ ++ ";"
debugIRSectionDef (Section name _) = "section " ++ toString name ++ ";"
debugIRSectionDef (IRDef def) = debugIRDef def
elabSection :: Text -> [IRSectionDef] -> ElabMonad [IRDef]
elabSection _name contents = saveState $ concat <$> forM contents elabDef
elabProgram :: IRProgram -> [IRDef]
elabProgram prog = evalState (elabSection "" prog) (SectionContext [] [])
pushVariable :: Text -> IRExpr -> SectionContext -> SectionContext
pushVariable name ty (SectionContext defs vars) = SectionContext defs ((name, ty) : vars)
pushDefinition :: Text -> [(Text, IRExpr)] -> SectionContext -> SectionContext
pushDefinition name defVars (SectionContext defs vars) = SectionContext ((name, defVars) : defs) vars
removeName :: Text -> ElabMonad ()
removeName name = do
modify $ over sectionDefsL (filter ((/= name) . fst))
modify $ over sectionVarsL (filter ((/= name) . fst))
extendVars :: Set (Text, IRExpr) -> ElabMonad (Set (Text, IRExpr))
extendVars vars = do
vars' <- foldr S.union S.empty <$> traverse (usedVars . snd) (S.toList vars)
if vars' `S.isSubsetOf` vars
then pure vars
else extendVars (vars `S.union` vars')
organize :: Set (Text, IRExpr) -> ElabMonad [(Text, IRExpr)]
organize found = do
vars <- gets sectionVars
pure $ reverse [var | var <- vars, var `S.member` found]
-- find all the section variables used in an expression
usedVars :: IRExpr -> ElabMonad (Set (Text, IRExpr))
usedVars (I.Var name) = do
varDeps <- maybe S.empty (S.singleton . (name,)) <$> lookupVar name
defDeps <- maybe S.empty S.fromList <$> lookupDef name
pure $ varDeps `S.union` defDeps
usedVars I.Star = pure S.empty
usedVars (I.Level _) = pure S.empty
usedVars (I.App m n) = S.union <$> usedVars m <*> usedVars n
usedVars (I.Abs name ty ascr body) = saveState $ do
ty' <- usedVars ty
ascr' <- traverse usedVars ascr
removeName name
S.union (ty' `S.union` (ascr' ?: S.empty)) <$> usedVars body
usedVars (I.Pi name ty ascr body) = saveState $ do
ty' <- usedVars ty
ascr' <- traverse usedVars ascr
removeName name
S.union (ty' `S.union` (ascr' ?: S.empty)) <$> usedVars body
usedVars (I.Let name ascr value body) = saveState $ do
ty' <- usedVars value
ascr' <- traverse usedVars ascr
removeName name
S.union (ty' `S.union` (ascr' ?: S.empty)) <$> usedVars body
-- traverse the body of a definition, adding the necessary section arguments to
-- any definitions made within the section
traverseBody :: IRExpr -> ElabMonad IRExpr
traverseBody (I.Var name) = do
mdeps <- lookupDef name
case mdeps of
Nothing -> pure $ I.Var name
Just deps -> pure $ foldl' (\acc newVar -> I.App acc (I.Var $ fst newVar)) (I.Var name) deps
traverseBody I.Star = pure I.Star
traverseBody (I.Level k) = pure $ I.Level k
traverseBody (I.App m n) = I.App <$> traverseBody m <*> traverseBody n
traverseBody (I.Abs name ty ascr body) = saveState $ do
ty' <- traverseBody ty
ascr' <- traverse traverseBody ascr
removeName name
I.Abs name ty' ascr' <$> traverseBody body
traverseBody (I.Pi name ty ascr body) = saveState $ do
ty' <- traverseBody ty
ascr' <- traverse traverseBody ascr
removeName name
I.Pi name ty' ascr' <$> traverseBody body
traverseBody (I.Let name ascr value body) = saveState $ do
ascr' <- traverse traverseBody ascr
value' <- traverseBody value
removeName name
I.Let name ascr' value' <$> traverseBody body
mkPi :: (Text, IRExpr) -> IRExpr -> IRExpr
mkPi (param, typ) = I.Pi param typ Nothing
mkAbs :: (Text, IRExpr) -> IRExpr -> IRExpr
mkAbs (param, typ) = I.Abs param typ Nothing
generalizeType :: IRExpr -> [(Text, IRExpr)] -> IRExpr
generalizeType = foldr mkPi
generalizeVal :: IRExpr -> [(Text, IRExpr)] -> IRExpr
generalizeVal = foldr mkAbs
elabDef :: IRSectionDef -> ElabMonad [IRDef]
elabDef (IRDef (Def name ty body)) = do
tyVars <- fromMaybe S.empty <$> traverse usedVars ty
bodyVars <- usedVars body
totalVars <- extendVars (tyVars `S.union` bodyVars) >>= organize
newBody <- traverseBody body
newType <- traverse traverseBody ty
modify $ pushDefinition name totalVars
pure [Def name (flip generalizeType totalVars <$> newType) (generalizeVal newBody totalVars)]
elabDef (IRDef (Axiom name ty)) = do
vars <- usedVars ty >>= extendVars >>= organize
modify $ pushDefinition name vars
pure [Axiom name (generalizeType ty vars)]
elabDef (Section name contents) = saveState $ elabSection name contents
elabDef (Variable name ty) = [] <$ modify' (pushVariable name ty)
saveBinders :: State Binders a -> State Binders a saveBinders :: State Binders a -> State Binders a
saveBinders action = do saveBinders action = do
binders <- get binders <- get
@ -179,6 +18,10 @@ saveBinders action = do
elaborate :: IRExpr -> Expr elaborate :: IRExpr -> Expr
elaborate ir = evalState (elaborate' ir) [] elaborate ir = evalState (elaborate' ir) []
where where
helper :: (Monad m) => Maybe a -> (a -> m b) -> m (Maybe b)
helper Nothing _ = pure Nothing
helper (Just x) f = Just <$> f x
elaborate' :: IRExpr -> State Binders Expr elaborate' :: IRExpr -> State Binders Expr
elaborate' (I.Var n) = do elaborate' (I.Var n) = do
binders <- get binders <- get
@ -188,12 +31,12 @@ elaborate ir = evalState (elaborate' ir) []
elaborate' (I.App m n) = E.App <$> elaborate' m <*> elaborate' n elaborate' (I.App m n) = E.App <$> elaborate' m <*> elaborate' n
elaborate' (I.Abs x t a b) = saveBinders $ do elaborate' (I.Abs x t a b) = saveBinders $ do
t' <- elaborate' t t' <- elaborate' t
a' <- traverse elaborate' a a' <- helper a elaborate'
modify (x :) modify (x :)
E.Abs x t' a' <$> elaborate' b E.Abs x t' a' <$> elaborate' b
elaborate' (I.Pi x t a b) = saveBinders $ do elaborate' (I.Pi x t a b) = saveBinders $ do
t' <- elaborate' t t' <- elaborate' t
a' <- traverse elaborate' a a' <- helper a elaborate'
modify (x :) modify (x :)
E.Pi x t' a' <$> elaborate' b E.Pi x t' a' <$> elaborate' b
elaborate' (I.Let name Nothing val body) = saveBinders $ do elaborate' (I.Let name Nothing val body) = saveBinders $ do

View file

@ -9,7 +9,6 @@ data Error
| NotEquivalent Expr Expr Expr | NotEquivalent Expr Expr Expr
| PNMissingType Text | PNMissingType Text
| DuplicateDefinition Text | DuplicateDefinition Text
| EmptySection Text
deriving (Eq, Ord) deriving (Eq, Ord)
instance ToText Error where instance ToText Error where
@ -19,7 +18,6 @@ instance ToText Error where
toText (NotEquivalent a a' e) = "Cannot unify '" <> pretty a <> "' with '" <> pretty a' <> "' when evaluating '" <> pretty e <> "'" toText (NotEquivalent a a' e) = "Cannot unify '" <> pretty a <> "' with '" <> pretty a' <> "' when evaluating '" <> pretty e <> "'"
toText (PNMissingType x) = "Axiom '" <> x <> "' missing type ascription" toText (PNMissingType x) = "Axiom '" <> x <> "' missing type ascription"
toText (DuplicateDefinition n) = "'" <> n <> "' already defined" toText (DuplicateDefinition n) = "'" <> n <> "' already defined"
toText (EmptySection var) = "Tried to declare variable " <> var <> " without a section"
instance ToString Error where instance ToString Error where
toString = toString . toText toString = toString . toText

View file

@ -143,12 +143,12 @@ helper k e@(Pi{}) = if k > 2 then parenthesize res else res
where where
(params, body) = collectPis e (params, body) = collectPis e
grouped = showParamGroup <$> groupParams params grouped = showParamGroup <$> groupParams params
res = "" <> unwords grouped <> " , " <> pretty body res = "" <> unwords grouped <> " . " <> pretty body
helper k e@(Abs{}) = if k >= 1 then parenthesize res else res helper k e@(Abs{}) = if k >= 1 then parenthesize res else res
where where
(params, body) = collectLambdas e (params, body) = collectLambdas e
grouped = showParamGroup <$> groupParams params grouped = showParamGroup <$> groupParams params
res = "λ " <> unwords grouped <> " => " <> pretty body res = "λ " <> unwords grouped <> " . " <> pretty body
helper _ e@(Let{}) = res helper _ e@(Let{}) = res
where where
(binds, body) = collectLets e (binds, body) = collectLets e

View file

@ -30,18 +30,6 @@ data IRExpr
} }
deriving (Show, Eq, Ord) deriving (Show, Eq, Ord)
data IRSectionDef
= Section
{ sectionName :: Text
, sectionContents :: [IRSectionDef]
}
| Variable
{ variableName :: Text
, variableType :: IRExpr
}
| IRDef IRDef
deriving (Show, Eq, Ord)
data IRDef data IRDef
= Def = Def
{ defName :: Text { defName :: Text
@ -52,6 +40,5 @@ data IRDef
{ axiomName :: Text { axiomName :: Text
, axiomAscription :: IRExpr , axiomAscription :: IRExpr
} }
deriving (Show, Eq, Ord)
type IRProgram = [IRSectionDef] type IRProgram = [IRDef]

View file

@ -34,7 +34,10 @@ eat :: Text -> Parser ()
eat = void . lexeme . chunk eat = void . lexeme . chunk
keywords :: [Text] keywords :: [Text]
keywords = ["forall", "let", "in", "end", "fun", "def", "axiom", "section", "variable", "hypothesis"] keywords = ["forall", "let", "in", "end", "fun", "def", "axiom"]
reservedChars :: [Char]
reservedChars = "();:"
pIdentifier :: Parser Text pIdentifier :: Parser Text
pIdentifier = try $ label "identifier" $ lexeme $ do pIdentifier = try $ label "identifier" $ lexeme $ do
@ -155,18 +158,6 @@ pNumSort = lexeme $ pSquare >> Level <$> (L.decimal <|> subscriptInt)
pSort :: Parser IRExpr pSort :: Parser IRExpr
pSort = lexeme $ pStar <|> try pNumSort <|> pSquare pSort = lexeme $ pStar <|> try pNumSort <|> pSquare
pTerm :: Parser IRExpr
pTerm = lexeme $ label "term" $ choice [pSort, pVar, between (char '(') (char ')') pIRExpr]
pAppTerm :: Parser IRExpr
pAppTerm = lexeme $ choice [pLAbs, pPAbs, pLet, pApp]
pIRExpr :: Parser IRExpr
pIRExpr = lexeme $ try pArrow <|> pAppTerm
pAscription :: Parser IRExpr
pAscription = lexeme $ try $ eat ":" >> label "type" pIRExpr
pAxiom :: Parser IRDef pAxiom :: Parser IRDef
pAxiom = lexeme $ label "axiom" $ do pAxiom = lexeme $ label "axiom" $ do
eat "axiom" eat "axiom"
@ -176,13 +167,6 @@ pAxiom = lexeme $ label "axiom" $ do
eat ";" eat ";"
pure $ Axiom ident ascription pure $ Axiom ident ascription
pVariable :: Parser [IRSectionDef]
pVariable = lexeme $ label "variable declaration" $ do
eat "variable" <|> eat "hypothesis"
vars <- pManyParams
eat ";"
pure $ uncurry Variable <$> vars
pDef :: Parser IRDef pDef :: Parser IRDef
pDef = lexeme $ label "definition" $ do pDef = lexeme $ label "definition" $ do
eat "def" eat "def"
@ -194,20 +178,23 @@ pDef = lexeme $ label "definition" $ do
eat ";" eat ";"
pure $ Def ident ascription $ foldr (mkAbs Nothing) body params pure $ Def ident ascription $ foldr (mkAbs Nothing) body params
pSection :: Parser IRSectionDef pIRDef :: Parser IRDef
pSection = lexeme $ label "section" $ do pIRDef = pAxiom <|> pDef
eat "section"
secLabel <- pIdentifier
body <- concat <$> many pIRDef
eat "end"
void $ lexeme $ chunk secLabel
pure $ Section secLabel body
pIRDef :: Parser [IRSectionDef] pTerm :: Parser IRExpr
pIRDef = (pure . IRDef <$> pAxiom) <|> (pure . IRDef <$> pDef) <|> pVariable <|> (pure <$> pSection) pTerm = lexeme $ label "term" $ choice [pSort, pVar, between (char '(') (char ')') pIRExpr]
pAppTerm :: Parser IRExpr
pAppTerm = lexeme $ choice [pLAbs, pPAbs, pLet, pApp]
pIRExpr :: Parser IRExpr
pIRExpr = lexeme $ try pArrow <|> pAppTerm
pAscription :: Parser IRExpr
pAscription = lexeme $ try $ eat ":" >> label "type" pIRExpr
pIRProgram :: Parser IRProgram pIRProgram :: Parser IRProgram
pIRProgram = skipSpace >> concat <$> some pIRDef pIRProgram = skipSpace >> some pIRDef
parserWrapper :: Parser a -> String -> Text -> Either String a parserWrapper :: Parser a -> String -> Text -> Either String a
parserWrapper p filename input = first errorBundlePretty $ runParser p filename input parserWrapper p filename input = first errorBundlePretty $ runParser p filename input
@ -216,7 +203,7 @@ parseProgram :: String -> Text -> Either String IRProgram
parseProgram = parserWrapper pIRProgram parseProgram = parserWrapper pIRProgram
parseDef :: String -> Text -> Either String IRDef parseDef :: String -> Text -> Either String IRDef
parseDef = parserWrapper (pAxiom <|> pDef) parseDef = parserWrapper pIRDef
parseExpr :: String -> Text -> Either String IRExpr parseExpr :: String -> Text -> Either String IRExpr
parseExpr = parserWrapper pIRExpr parseExpr = parserWrapper pIRExpr

View file

@ -41,7 +41,7 @@ evalDef :: Env -> IRDef -> Result Env
evalDef = flip (execStateT . handleDef) evalDef = flip (execStateT . handleDef)
handleProgram :: Env -> IRProgram -> Result Env handleProgram :: Env -> IRProgram -> Result Env
handleProgram env = flip execStateT env . mapM_ handleDef . elabProgram handleProgram env = flip execStateT env . mapM_ handleDef
handleAndParseProgram :: Env -> String -> Text -> Either String Env handleAndParseProgram :: Env -> String -> Text -> Either String Env
handleAndParseProgram env filename input = (first toString . handleProgram env) =<< parseProgram filename input handleAndParseProgram env filename input = (first toString . handleProgram env) =<< parseProgram filename input