diff --git a/.gitmodules b/.gitmodules index f2c90a1cad..1bbf1fd2bd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1193,6 +1193,9 @@ [submodule "vendor/grammars/sublime-golo"] path = vendor/grammars/sublime-golo url = https://github.com/TypeUnsafe/sublime-golo +[submodule "vendor/grammars/sublime-lambdapi"] + path = vendor/grammars/sublime-lambdapi + url = https://github.com/Deducteam/sublime-lambdapi.git [submodule "vendor/grammars/sublime-mask"] path = vendor/grammars/sublime-mask url = https://github.com/tenbits/sublime-mask diff --git a/grammars.yml b/grammars.yml index 9da8a9b6a2..53d5b8ce9c 100644 --- a/grammars.yml +++ b/grammars.yml @@ -1073,6 +1073,8 @@ vendor/grammars/sublime-glsl: - source.glsl vendor/grammars/sublime-golo: - source.golo +vendor/grammars/sublime-lambdapi: +- source.lp vendor/grammars/sublime-mask: - source.mask vendor/grammars/sublime-nearley: diff --git a/lib/linguist/heuristics.yml b/lib/linguist/heuristics.yml index ddaacd9e6b..2555e2ccae 100644 --- a/lib/linguist/heuristics.yml +++ b/lib/linguist/heuristics.yml @@ -443,6 +443,8 @@ disambiguations: pattern: '^import [A-Z]' - extensions: ['.lp'] rules: + - language: Lambdapi + pattern: '(?:^|\s)symbol(?:$|\s)|(?:^|\s)rule(?:$|\s)' - language: Linear Programming pattern: '^(?i:minimize|minimum|min|maximize|maximum|max)(?i:\s+multi-objectives)?$' - language: Answer Set Programming diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index 971b8138eb..fa7ab7ba5b 100644 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -4011,6 +4011,14 @@ LabVIEW: codemirror_mode: xml codemirror_mime_type: text/xml language_id: 194 +Lambdapi: + type: programming + color: "#8027a3" + extensions: + - ".lp" + tm_scope: source.lp + ace_mode: text + language_id: 759240513 Lark: type: data color: "#2980B9" diff --git a/samples/Lambdapi/List.lp b/samples/Lambdapi/List.lp new file mode 100644 index 0000000000..e4acd2be82 --- /dev/null +++ b/samples/Lambdapi/List.lp @@ -0,0 +1,342 @@ +require open tests.OK.Set tests.OK.Prop tests.OK.FOL tests.OK.Eq + tests.OK.Nat tests.OK.Bool; + +(a:Set) inductive 𝕃:TYPE ≔ +| β–‘ : 𝕃 a // \Box +| βΈ¬ : Ο„ a β†’ 𝕃 a β†’ 𝕃 a; // :: + +notation βΈ¬ infix right 20; + +// set code for 𝕃 + +constant symbol list : Set β†’ Set; + +rule Ο„ (list $a) β†ͺ 𝕃 $a; + +// isβ–‘ + +symbol isβ–‘ [a]: 𝕃 a β†’ 𝔹; + +rule isβ–‘ β–‘ β†ͺ true +with isβ–‘ (_ βΈ¬ _) β†ͺ false; + +// non confusion of constructors + +opaque symbol βΈ¬β‰ β–‘ [a] [x:Ο„ a] [l] : Ο€ (x βΈ¬ l β‰  β–‘) ≔ +begin + assume a x l h; refine ind_eq h (Ξ» l, istrue(isβ–‘ l)) ⊀ᡒ +end; + +opaque symbol β–‘β‰ βΈ¬ [a] [x:Ο„ a] [l] : Ο€ (β–‘ β‰  x βΈ¬ l) ≔ +begin + assume a x l h; apply @βΈ¬β‰ β–‘ a x l; symmetry; apply h +end; + +// head + +symbol head [a] : Ο„ a β†’ 𝕃 a β†’ Ο„ a; + +rule head $x β–‘ β†ͺ $x +with head _ ($x βΈ¬ _) β†ͺ $x; + +// tail + +symbol behead [a] : 𝕃 a β†’ 𝕃 a; + +rule behead β–‘ β†ͺ β–‘ +with behead (_ βΈ¬ $l) β†ͺ $l; + +// injectivity of constructors + +opaque symbol βΈ¬_inj [a] [x:Ο„ a] [l y m] : Ο€(x βΈ¬ l = y βΈ¬ m) β†’ Ο€(x = y ∧ l = m) ≔ +begin + assume a x l y m e; apply ∧ᡒ { refine feq (head x) e } { refine feq behead e } +end; + +// boolean equality on lists + +symbol eql [a] : (Ο„ a β†’ Ο„ a β†’ 𝔹) β†’ 𝕃 a β†’ 𝕃 a β†’ 𝔹; + +rule eql _ β–‘ β–‘ β†ͺ true +with eql _ (_ βΈ¬ _) β–‘ β†ͺ false +with eql _ β–‘ (_ βΈ¬ _) β†ͺ false +with eql $beq ($x βΈ¬ $l) ($y βΈ¬ $m) β†ͺ ($beq $x $y) and (eql $beq $l $m); + +opaque symbol eql_correct a (beq:Ο„ a β†’ Ο„ a β†’ 𝔹) : + Ο€(`βˆ€ x, `βˆ€ y, beq x y β‡’ x = y) β†’ Ο€(`βˆ€ l, `βˆ€ m, eql beq l m β‡’ l = m) ≔ +begin + assume a beq beq_correct; induction + { induction + { reflexivity } + { simplify; assume y m i c; refine βŠ₯β‚‘ c } + } + { assume x l h; induction + { simplify; assume c; refine βŠ₯β‚‘ c; } + { simplify; assume y m i c; + apply feq2 (βΈ¬) _ _ + { apply beq_correct; apply @andₑ₁ _ (eql beq l m) c } + { apply h; refine @andβ‚‘β‚‚ (beq x y) _ c + } + } + } +end; + +opaque symbol eql_complete a (beq : Ο„ a β†’ Ο„ a β†’ 𝔹) : + Ο€(`βˆ€ x, `βˆ€ y, x = y β‡’ beq x y) β†’ Ο€(`βˆ€ l, `βˆ€ m, l = m β‡’ eql beq l m) ≔ +begin + assume a beq beq_complete; induction + { assume m i; rewrite left i; apply ⊀ᡒ; } + { assume x l h; induction + { assume j; apply βΈ¬β‰ β–‘ j; } + { assume y m i j; simplify; + have j': Ο€(x = y ∧ l = m) { apply βΈ¬_inj j }; + apply @istrue_and (beq x y) (eql beq l m); apply ∧ᡒ + { apply beq_complete x y; apply βˆ§β‚‘β‚ j' } + { apply h m; apply βˆ§β‚‘β‚‚ j' } + } + } +end; + +// size + +symbol size [a] : 𝕃 a β†’ β„•; + +rule size β–‘ β†ͺ 0 +with size (_ βΈ¬ $l) β†ͺ size $l +1; + +opaque symbol size0nil [a] (l:𝕃 a) : Ο€ (size l = 0) β†’ Ο€ (l = β–‘) ≔ +begin + assume a; induction + { reflexivity; } + { assume e l h i; apply βŠ₯β‚‘; apply sβ‰ 0 i; } +end; + +symbol nilp [a] l ≔ is0 (@size a l); + +opaque symbol size_behead [a] (l:𝕃 a) : Ο€ (size (behead l) = size l ∸1) ≔ +begin + assume a; induction + { reflexivity; } + { assume e l h; reflexivity; } +end; + +// concatenation + +symbol ++ [a] : 𝕃 a β†’ 𝕃 a β†’ 𝕃 a; notation ++ infix right 30; // \cdot + +assert x y z ⊒ x ++ y ++ z ≑ x ++ (y ++ z); +assert x l m ⊒ x βΈ¬ l ++ m ≑ x βΈ¬ (l ++ m); + +rule β–‘ ++ $m β†ͺ $m +with ($x βΈ¬ $l) ++ $m β†ͺ $x βΈ¬ ($l ++ $m); + +opaque symbol cat0s [a] (l:𝕃 a) : Ο€ (β–‘ ++ l = l) ≔ +begin + reflexivity; +end; + +opaque symbol cat1s [a] (x:Ο„ a) l : Ο€ ((x βΈ¬ β–‘) ++ l = (x βΈ¬ l)) ≔ +begin + reflexivity; +end; + +opaque symbol cat_cons [a] (x:Ο„ a) l1 l2 : Ο€ ((x βΈ¬ l1) ++ l2 = x βΈ¬ (l1 ++ l2)) ≔ +begin + reflexivity; +end; + +// nseq + +symbol nseq [a] : β„• β†’ Ο„ a β†’ 𝕃 a; + +rule nseq 0 _ β†ͺ β–‘ +with nseq ($n +1) $x β†ͺ $x βΈ¬ (nseq $n $x); + +// ncons + +symbol ncons [a] : β„• β†’ Ο„ a β†’ 𝕃 a β†’ 𝕃 a; + +rule ncons 0 _ $l β†ͺ $l +with ncons ($n +1) $x $l β†ͺ $x βΈ¬ ncons $n $x $l; + +opaque symbol size_ncons [a] n (x:Ο„ a) l : Ο€ (size (ncons n x l) = n + size l) ≔ +begin + assume a; induction + { reflexivity; } + { assume n h x l; simplify; apply feq (+1) (h x l); } +end; + +opaque symbol size_nseq [a] n (x:Ο„ a) : Ο€ (size (nseq n x) = n) ≔ +begin + assume a; induction + { reflexivity; } + { assume n h x; simplify; apply feq (+1) (h x); } +end; + +opaque symbol cat_nseq [a] n (x:Ο„ a) l : Ο€ (nseq n x ++ l = ncons n x l) ≔ +begin + assume a; induction + { reflexivity; } + { assume n h x l; simplify; rewrite h x l; reflexivity; } +end; + +opaque symbol nseqD [a] n1 n2 (x:Ο„ a) : + Ο€ (nseq (n1 + n2) x = nseq n1 x ++ nseq n2 x) ≔ +begin + assume a; induction + { reflexivity; } + { assume n1 h n2 x; simplify; rewrite h n2; reflexivity; } +end; + +opaque symbol cats0 [a] (l:𝕃 a) : Ο€(l ++ β–‘ = l) ≔ +begin + assume a; + induction + // case l = β–‘ + { reflexivity; } + // case l = x βΈ¬ l' + { assume x l' h; simplify; rewrite h; reflexivity; } +end; + +rule $m ++ β–‘ β†ͺ $m; + +opaque symbol size_cat [a] (l m : 𝕃 a) : Ο€(size (l ++ m) = size l + size m) ≔ +begin + assume a; + induction + // case l = β–‘ + { reflexivity; } + // case l = xβΈ¬l' + { assume x l' h m; simplify; rewrite h; reflexivity; } +end; + +rule size ($l ++ $m) β†ͺ size $l + size $m; + +opaque symbol catA [a] (l m n : 𝕃 a) : Ο€((l ++ m) ++ n = l ++ (m ++ n)) ≔ +begin + assume a; + induction + // case l = β–‘ + { reflexivity; } + // case l = xβΈ¬l' + { assume x l' h m n; simplify; rewrite h; reflexivity; } +end; + +rule ($l ++ $m) ++ $n β†ͺ $l ++ ($m ++ $n); + +opaque symbol cat_nilp [a] (l1 l2 : 𝕃 a) : + Ο€ (nilp (l1 ++ l2) = (nilp l1 and nilp l2)) ≔ +begin + assume a; induction + { reflexivity; } + { assume e l h l2; simplify; reflexivity; } +end; + +// list reversal + +symbol rev [a] : 𝕃 a β†’ 𝕃 a; + +rule rev β–‘ β†ͺ β–‘ +with rev ($x βΈ¬ $l) β†ͺ rev $l ++ ($x βΈ¬ β–‘); + +opaque symbol rev_concat [a] (l m : 𝕃 a) : Ο€(rev (l ++ m) = rev m ++ rev l) ≔ +begin + assume a; + induction + // case l = β–‘ + { simplify; reflexivity; } + // case l = βΈ¬ + { assume x l h m; simplify; rewrite h; reflexivity; } +end; + +rule rev ($l ++ $m) β†ͺ rev $m ++ rev $l; + +opaque symbol rev_idem [a] (l :𝕃 a) : Ο€(rev (rev l) = l) ≔ +begin + assume a; induction + { reflexivity } + { assume x l h; simplify; rewrite h; reflexivity } +end; + +opaque symbol size_rev [a] (l : 𝕃 a) : Ο€(size (rev l) = size l) ≔ +begin + assume a; + induction + // case l = β–‘ + { simplify; reflexivity; } + // case l = βΈ¬ + { assume x l h; simplify; rewrite h; reflexivity; } +end; + +// rcons + +symbol rcons [a] : 𝕃 a β†’ Ο„ a β†’ 𝕃 a; + +rule rcons β–‘ $x β†ͺ $x βΈ¬ β–‘ +with rcons ($e βΈ¬ $l) $x β†ͺ $e βΈ¬ (rcons $l $x); + +opaque symbol cats1 [a] (l:𝕃 a) (z:Ο„ a) : Ο€ (l ++ (z βΈ¬ β–‘) = rcons l z) ≔ +begin + assume a; induction + { reflexivity; } + { assume e l h z; simplify; rewrite h z; reflexivity; } +end; + +opaque symbol rcons_cons [a] (x:Ο„ a) (s:𝕃 a) (z:Ο„ a) : + Ο€ (rcons (x βΈ¬ s) z = x βΈ¬ rcons s z) ≔ +begin + reflexivity; +end; + +// Arr + +symbol Arr : β„• β†’ Set β†’ Set β†’ TYPE; + +rule Arr 0 _ $b β†ͺ Ο„ $b +with Arr ($n +1) $a $b β†ͺ Ο„ $a β†’ Arr $n $a $b; + +// seqn + +symbol seqn_acc [a] n : 𝕃 a β†’ Arr n a (list a); + +rule seqn_acc 0 $l β†ͺ rev $l +with seqn_acc ($n +1) $l $x β†ͺ seqn_acc $n ($x βΈ¬ $l); + +symbol seqn [a] n ≔ @seqn_acc a n β–‘; + +assert a (x y : Ο„ a) ⊒ seqn 2 x y ≑ x βΈ¬ y βΈ¬ β–‘; + +// iota + +symbol iota : β„• β†’ β„• β†’ 𝕃 nat; +rule iota _ 0 β†ͺ β–‘ +with iota $n ($k +1) β†ͺ $n βΈ¬ iota ($n +1) $k; + +assert ⊒ iota 1 2 ≑ 1 βΈ¬ 2 βΈ¬ β–‘; + +// indexes + +symbol indexes [a] : 𝕃 a β†’ 𝕃 nat; + +rule indexes $l β†ͺ iota 0 (size $l); + +assert x ⊒ indexes (x βΈ¬ x βΈ¬ x βΈ¬ x βΈ¬ β–‘) ≑ 0 βΈ¬ 1 βΈ¬ 2 βΈ¬ 3 βΈ¬ β–‘; + +// last + +symbol last [a] : Ο„ a β†’ 𝕃 a β†’ Ο„ a; + +rule last $x β–‘ β†ͺ $x +with last _ ($e βΈ¬ $l) β†ͺ last $e $l; + +assert ⊒ last 4 (3 βΈ¬ 2 βΈ¬ 1 βΈ¬ β–‘) ≑ 1; +assert ⊒ last 4 β–‘ ≑ 4; + +// belast + +symbol belast [a] : Ο„ a β†’ 𝕃 a β†’ 𝕃 a; + +rule belast _ β–‘ β†ͺ β–‘ +with belast $x ($e βΈ¬ $l) β†ͺ $x βΈ¬ belast $e $l; + +assert ⊒ belast 4 (3 βΈ¬ 2 βΈ¬ 1 βΈ¬ β–‘) ≑ 4 βΈ¬ 3 βΈ¬ 2 βΈ¬ β–‘; diff --git a/samples/Lambdapi/tutorial.lp b/samples/Lambdapi/tutorial.lp new file mode 100644 index 0000000000..35e46cba78 --- /dev/null +++ b/samples/Lambdapi/tutorial.lp @@ -0,0 +1,349 @@ +// Learn the basics of Lambdapi in 15 minutes (this is a one-line comment). + +/* Install support for Lambdapi files in Emacs or VSCode to better +visualize this file and the generated subgoals in proofs +(this is a multi-lines comment). */ + +/* Put this file and +https://github.com/Deducteam/lambdapi/blob/master/tests/lambdapi.pkg +in the same directory, and run emacs or vscode from this +directory. Make sure that lambdapi is in your path (do "eval `opam +env`" if you installed lambdapi with opam). */ + +/* In Lambdapi, you can declare type and object symbols. Symbol names +can contain unicode characters (utf8). */ + +/* Convention: identifiers starting with an uppercase letter denote +types, while identifiers starting with a lowercase letter denote objects. */ + +symbol β„• : TYPE; // is a type declaration + +// Commands are separated by semi-colons. + +symbol zero : β„•; // is an object declaration + +symbol succ : β„• β†’ β„•; /* means that "succ" takes an argument of type β„• + and returns something of type β„•. */ + +// We can make definitions as follows: +symbol one ≔ succ zero; + +// We can ask Lambdapi the type of a term: +type one; + +// We can check that a term has a given type: +assert ⊒ one : β„•; + +// or that a term does not have a given type: +assertnot ⊒ succ : β„•; + +symbol + : β„• β†’ β„• β†’ β„•; +notation + infix right 10; +/* means that + is declared as infix. +"right" means that "x + y + z" is the same as "x + (y + z)". +10 is the priority level of +. It is useful to parse expressions +with various infix operators (see below). */ + +symbol Γ— : β„• β†’ β„• β†’ β„•; +notation Γ— infix right 20; +/* The priority level of Γ— is higher than the one of +. +So "x + y Γ— z" is parsed as "x + (y Γ— z)". We can check it as follows: */ + +assert x y z ⊒ x + y Γ— z ≑ x + (y Γ— z); +assertnot x y z ⊒ x + y Γ— z ≑ (x + y) Γ— z; + +/* We can now tell Lambdapi to identify any term of the form "t + 0" with "t" +by simply declaring the following rewrite rule: */ +rule $x + zero β†ͺ $x; // rule variables must be prefixed by "$" + +// We can also ask Lambdapi to evaluate a term using the declared rules: +compute zero + zero; +// and check the result: +assert ⊒ zero + zero ≑ zero; + /* ≑ is the equational theory generated by the user-defined rules + and Ξ²-reduction + Ξ·-reduction if the flag "eta_equality" is on. */ + +// The definition of + can be completed by adding a new rule later: +rule $x + succ $y β†ͺ succ ($x + $y); + +// Several rules can also be given at once: +rule zero Γ— $y β†ͺ zero +with succ $x Γ— $y β†ͺ $y + $x Γ— $y; + +/* We now would like to prove some theorem about +. To this end, since +Lambdapi does not come with a pre-defined logic, we first need to +define what is a proposition and what is a proof. + +You usually just need to install a package defining some logics and +require it in your development. For instance, using Opam, you can do: + +opam install lambdapi-logics + +Then, in your development, you can use one of the logics defined in +this package (see https://github.com/Deducteam/lambdapi-logics for +more details) as follows: + +require Logic.TFF.Main; + +This tells Lambdapi to load in the environment the symbols, rules, +etc. declared in the package Logic.TFF, which defines multi-sorted +first-order logic. A symbol f of Logic.TFF can then be refered to by +Logic.TFF.f. To avoid writing Logic.TFF every time, you can do: + +open Logic.TFF.Main; + +The two operations can also be done at the same time by simply writing; + +require open Logic.TFF; + +But we are going to define our own logic hereafter to show that it is +simple. */ + +// We first declare a type for propositions: +symbol Prop : TYPE; + +// and symbols for building propositions: +symbol = : β„• β†’ β„• β†’ Prop; +notation = infix 1; + +/* We then use the "proposition-as-type" technique to reduce +proof-checking to type-checking. To this end, we define a type for the +proofs of a proposition: */ +injective symbol Prf : Prop β†’ TYPE; + /* Note that this is a type-level function, that is, a function that + takes as argument a term of type Prop and return a term of type TYPE. + + Moreover, we declare Prf as injective. This means that Prf + should satisfy the following property: + if Prf(p) ≑ Prf(q) then p ≑ q. + The verification of this property is left to the user. + This information is used by Lambdapi to simplify a unification constraint + of the form Prf(p) ≑ Prf(q) into p ≑ q (see below). */ + +/* We then say that a proof of a proposition "p" is any term of type +"Prf(p)". We therefore need to declare axioms saying which +propositions are true. For instance, a usual axiom for equality is +that it is a reflexive relation: */ +symbol =-refl x : Prf(x = x); + /* For all x, "=-refl x" is a proof of the proposition "x = x". + Note that Lambdapi can infer the type of "x" automatically: + the user does not need to write "symbol =-refl (x : β„•) : Prf(x = x)". */ + +/* Another usual axiom is that function application preserves equality: */ +symbol =-succ x y : Prf(x = y) β†’ Prf(succ x = succ y); + +/* We also need to declare that we can prove any proposition "p" on natural +numbers by induction: */ +symbol ind_β„• (p : β„• β†’ Prop) + (case-zero : Prf(p zero)) + (case-succ : Ξ  x : β„•, Prf(p x) β†’ Prf(p (succ x))) + /* While "A β†’ B" is the Lambdapi type of functions from "A" to "B", + "Ξ  x : A, B(x)" is the Lambdapi type of so-called "dependent" functions + since x may occur in B(x). This is the type of functions mapping + any element a of type A to some element of type B(a). + It boils down to "A β†’ B" if x does not occur in B. + Hence, case-succ is a function that takes as arguments a natural + number x and a proof that "p x" is true, and returns a proof that + "p (succ x)" is true. */ + (n : β„•) + : Prf(p n); + +/* We will later see that this induction principle can in fact be +automatically generated by Lambdapi by using the "inductive" command +when declaring β„•, zero and succ. */ + +/* We are now ready to prove that, for any natural number "x", +"zero + x" is equal to "x", that is, to show that there exists a term, that +we will call "zero_is_neutral_for_+", of type "Ξ  x : β„•, Prf (zero + x = x)". +To this end, Lambdapi provides an interactive mode (launched by the keyword +"begin") to enable users to define this term step by step using tactics. */ + +opaque /* We declare the symbol as opaque as we do not want Lambdapi +to unfold it later. */ +symbol zero_is_neutral_for_+ x : Prf (zero + x = x) ≔ + +begin +/* Here, in Emacs or VSCode, the system prints the following goal to prove: +?zero_is_neutral_for_+: Ξ  x: β„•, Prf ((zero + x) = x) */ + +/* To proceed by induction on x, we simply need to say that +?zero_is_neutral_for_+ should be of the form "ind_β„• _ _ _" +where "_" stands for a term to be built. +This can be done by using the "refine" tactic: */ + +/* However, if we simply write "refine ind_β„• _ _ _", +Lambdapi will complain with the following error message: +"Missing subproofs (0 subproofs for 2 subgoals)." +This is because we gave no subproof for the case-zero and case-succ arguments. +Indeed, in Lambdapi, proofs must be well structured, that is, a tactic +must be followed by as many subproofs enclosed between curly brackets +as the number of subgoals generated by the tactic. So, here, we need to write +"refine nat _ _ _ {} {}" and then write the missing subproofs. */ + +/* Remark: if we hadn't declared Prf as injective, we would have gotten + 4 subgoals. the first generated subgoal would not have been a typing goal + but the following unification goal: + "Prf (?4 n) ≑ Prf ((zero + n) = n)" + where "?4" stands for the unknown predicate "p" that we try to prove, + which would have been the second goal, the third goal being the case for + zero, and the fourth goal being the case for succ. + This is one of the interesting features of Lambdapi to have unification + goals. However, currently, Lambdapi has only one tactic for unification + goals, namely "solve", which is applied automatically and thus didn't work + here. However, we can see that, to simplify this unification goal to + "?4 n ≑ (zero + n) = n" + we need Prf to be injective. */ + +refine ind_β„• _ _ _ + { /* Here comes the proof of the first generated subgoal: + "Prf ((zero + zero) = zero)". + + Note that Lambdapi infered the predicate to prove automatically. + + To prove the first subgoal, we can first ask Lambdapi to simplify it + by applying user-defined rewriting rules with the tactic "simplify": */ + simplify; + + /* We then get the following goal: + "Prf (zero = zero)" + which can be solved by using =-refl: */ + refine =-refl zero; + } + { /* Here comes the proof of the second generated subgoal: + "Ξ  x: β„•, Prf ((zero + x) = x) β†’ Prf ((zero + succ x) = succ x)" + + We start by assuming a given x : β„• such that "zero + x = x" + using the tactic "assume": */ + assume x hyp_on_x; + /* Again, we can simplify the goal: */ + simplify; + /* We can then conclude by using the axiom =-succ and the assumption + hyp_on_x: */ + refine =-succ (zero + x) x hyp_on_x; + /* Alternatively, we could use the "rewrite" tactic of Lambdapi, + to replace "zero + x" by "x", but this requires to set up a number + of "builtins" (see below). */ + }; +end; + +/* Remark: now that we proved that "zero + x" is equal to "x", we can turn +this equality into a rewrite rule to reason modulo this rule automatically. */ +rule zero + $y β†ͺ $y; + +/* We are going to see below how this first proof can be simplified +by using more advanced features of Lambdapi. */ + +/* First, the induction principle on natural numbers can be automatically +generated by Lambdapi by using the command "inductive", +as long as the builtins "Prop" and "P" are set: */ +builtin "Prop" ≔ Prop; +builtin "P" ≔ Prf; +inductive Nat : TYPE ≔ z : Nat | s : Nat β†’ Nat; + +/* To see what has been generated, you can write: */ +print Nat; +/* prints: + +constant symbol Nat: TYPE + +constructors: + z: Nat + s: Nat β†’ Nat + +induction principle: + ind_Nat: Ξ  p0: (Nat β†’ Prop), P (p0 z) β†’ (Ξ  x0: Nat, P (p0 x0) β†’ P (p0 (s x0))) β†’ Ξ  x0: Nat, P (p0 x0) +*/ +print ind_Nat; +/* prints: + +symbol ind_Nat +: Ξ  p0: (Nat β†’ Prop), P (p0 z) β†’ (Ξ  x0: Nat, P (p0 x0) β†’ P (p0 (s x0))) β†’ Ξ  x0: Nat, P (p0 x0) + +rules: + ind_Nat $v0_p0 $v1_z $v2_s z β†ͺ $v1_z + ind_Nat $v0_p0 $v1_z $v2_s (s $v3_x0) β†ͺ $v2_s $v3_x0 (ind_Nat $v0_p0 $v1_z $v2_s $v3_x0) +*/ +print one; // to see the definition of ten +print +; // to see the type, notation and rules of + + +/* It is also possible now to replace the tactic "refine ind_Nat _ _ _" +by a call to the tactic "induction" (see below). */ + +/* Similarly, we can define a type for lists of natural numbers: */ +inductive List_Nat : TYPE ≔ +| nil_Nat : List_Nat +| cons_Nat : Nat β†’ List_Nat β†’ List_Nat; + +/* But what if we want to have lists of booleans, or lists of lists of +natural numbers, etc.? Lambdapi does not allow to quantify over +types. On the other hand, it is possible to interpret objects as types +using type-level rewriting rules, in the same way the function Prf +maps terms of type Prop to types. We can define polymorphic objects by +defining a type for type codes, and quantify over type codes instead +of types: */ + +symbol Set : TYPE; // type for type codes +injective symbol Ο„ : Set β†’ TYPE; // function interpreting type codes as types + +// For instance, we can define a code for Nat: +symbol nat : Set; +rule Ο„ nat β†ͺ Nat; + +// We can now define polymorphic lists: + +(a:Set) inductive 𝕃:TYPE ≔ +| β–‘ /* \Box */ : 𝕃 a +| βΈ¬ /* :: */ : Ο„ a β†’ 𝕃 a β†’ 𝕃 a; + +/* We are now going to see how to use tactics related to equality like +"reflexivity", "symmetry" and "rewrite". To this end, we need to use a +polymorphic equality and define a few more builtins that are necessary +for Lambdapi to generate the corresponding proofs. */ + +constant // means that we cannot add rules later +symbol ≃ [a] /* arguments between square brackets are implicit +and must not be written later, unless they are enclosed between square brackets +or if the symbol is prefixed by "@". */ +: Ο„ a β†’ Ο„ a β†’ Prop; + +notation ≃ infix 1; + +constant symbol ≃-refl [a] (x:Ο„ a) : Prf(x ≃ x); +constant symbol ≃-ind [a] [x y:Ο„ a] : Prf(x ≃ y) β†’ Ξ  p, Prf(p y) β†’ Prf(p x); + // Leibniz principle. + +builtin "T" ≔ Ο„; +builtin "eq" ≔ ≃; +builtin "refl" ≔ ≃-refl; +builtin "eqind" ≔ ≃-ind; + +/* We now reprove our theorem on the inductive type Nat instead of β„•, +using the tactics "induction", "reflexivity" and "rewrite". +To this end, we first need to define addition on Nat: */ + +symbol βŠ• : Nat β†’ Nat β†’ Nat; +notation βŠ• infix right 10; +rule $x βŠ• z β†ͺ $x +with $x βŠ• s $y β†ͺ s ($x βŠ• $y); + +opaque symbol zero_is_neutral_for_βŠ• x : Prf(z βŠ• x ≃ x) ≔ +begin +induction + { simplify; reflexivity; } + { assume x hyp_on_x; simplify; rewrite hyp_on_x; reflexivity; } +end; + +/* Note finally that a development can be split into several +files. For instance, imagine that your development is made of file1.lp +and file2.lp, and that file2.lp uses symbols defined in +file1.lp. Then, you should create a file lambdapi.pkg with the +following two lines: + +package_name = my_package +root_path = my_package + +where my_package is the name of your package. Then, at the beginning +of file2.lp, you should add: + +require my_package.file1; +*/ diff --git a/vendor/README.md b/vendor/README.md index a0ceb6b4e5..77a953e64c 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -331,6 +331,7 @@ This is a list of grammars that Linguist selects to provide syntax highlighting - **LSL:** [textmate/secondlife-lsl.tmbundle](https://github.com/textmate/secondlife-lsl.tmbundle) - **LTspice Symbol:** [Alhadis/language-pcb](https://github.com/Alhadis/language-pcb) - **LabVIEW:** [textmate/xml.tmbundle](https://github.com/textmate/xml.tmbundle) +- **Lambdapi:** [Deducteam/sublime-lambdapi](https://github.com/Deducteam/sublime-lambdapi) - **Lark:** [Alhadis/language-grammars](https://github.com/Alhadis/language-grammars) - **Lasso:** [bfad/Sublime-Lasso](https://github.com/bfad/Sublime-Lasso) - **Latte:** [textmate/php-smarty.tmbundle](https://github.com/textmate/php-smarty.tmbundle) diff --git a/vendor/grammars/sublime-lambdapi b/vendor/grammars/sublime-lambdapi new file mode 160000 index 0000000000..3f6ecece6c --- /dev/null +++ b/vendor/grammars/sublime-lambdapi @@ -0,0 +1 @@ +Subproject commit 3f6ecece6c9fdc39133804cb31f7e6f20b64ff8a diff --git a/vendor/licenses/git_submodule/sublime-lambdapi.dep.yml b/vendor/licenses/git_submodule/sublime-lambdapi.dep.yml new file mode 100644 index 0000000000..b374aab2e4 --- /dev/null +++ b/vendor/licenses/git_submodule/sublime-lambdapi.dep.yml @@ -0,0 +1,31 @@ +--- +name: sublime-lambdapi +version: 3f6ecece6c9fdc39133804cb31f7e6f20b64ff8a +type: git_submodule +homepage: https://github.com/Deducteam/sublime-lambdapi.git +license: mit +licenses: +- sources: LICENSE + text: |- + The MIT License (MIT) + + Copyright (c) 2014 Inria + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +notices: []