[{"data":1,"prerenderedAt":4},["ShallowReactive",2],{"wY58Up0Gmk":3},"# Natural Lean\n\n![cancellation of addition](images/cancel_addition.png)\n\nNatural Lean is a library that lets you write Lean definitions, theorems, and proofs in a controlled natural language that looks much like ordinary mathematical English.  To use the library, you can simply write `import Natural` at the top of a Lean source file, then write natural-language mathematics freely in the rest of the file.  If you are using an IDE such as Visual Studio Code, Natural Lean will automatically translate your text into native Lean code, which will be checked for correctness.\n\nFor a first glimpse of Natural Lean you could look at the file [`examples/nat_num_game.lean`](examples/nat_num_game.lean), which proves all of the theorems from the [Natural Number Game](https://adam.math.hhu.de/#/g/leanprover-community/nng4).  (Actually there are not many  explicit proofs in this file, since Natural Lean's [default tactic](#tactics) can solve most of these problems directly.)  The file [`examples/nat.lean`](examples/nat.lean) is more substantial, and includes a partial development of the natural numbers from first principles in Natural Lean, including a number of theorems with proofs.   (To see the full proofs in this file, you will want to turn on word wrap.  As one possibility, download the file, view it in Visual Studio Code, and press Alt+Z to enable wrapping.)  \n\nNatural Lean is in an __early stage of development__ and is not a practical tool for writing many Lean proofs at this time: the grammar and expressiveness of the language are still extremely limited.  You may nevertheless want to experiment with Natural Lean even in its current state.  Your feedback is welcome: you can send me [email](mailto:adam.dingle@mff.cuni.cz) or open issues in this repository.  I am actively developing the library and will be adding more features over time.\n\n### Contents\n\n- [Getting started](#getting-started)\n- [Definitions](#definitions)\n- [Theorems](#theorems)\n  - [Theorem groups](#theorem-groups)\n- [Proofs](#proofs)\n  - [Sequences of proof steps](#sequences-of-proof-steps)\n- [Propositions](#propositions)\n  - [Operator chains](#operator-chains)\n- [Expressions](#expressions)\n- [Types](#types)\n- [Natural names](#natural-names)\n- [Tactics](#tactics)\n- [Visual Studio Code integration](#visual-studio-code-integration)\n- [Hints and tips](#hints-and-tips)\n  - [Proving steps](#proving-steps)\n  - [Grammar](#grammar)\n  - [Debugging](#debugging)\n     \n(Tip: If you are viewing this document on GitHub's web site, you can also click the table of contents icon in the upper right to navigate through the various sections.)\n\n### Getting started\nIn your project's `lakefile.toml` file, write\n\n```\n[[require]]\nname = \"natural\"\ngit = \"https://github.com/medovina/natural_lean.git\"\nrev = \"main\"\n```\n\nAt the top of any Lean source file in your project, write\n\n```\nimport Natural\n```\n\nAfter that, you can mix natural-language mathematics with native Lean code freely in the same file.\n\n\n### Definitions\n\nA definition begins with the capitalized word `Definition`.  Three limited kinds of definitions are currently supported.  An _inductive type definition_ defines a new type with one or more constructors:\n\n```\nDefinition.  The type ℕ is defined inductively with constructors 0 : ℕ and S : ℕ → ℕ.\n```\n\nA _definition by cases_ defines a function recursively with one or more cases.  Currently the function must be a supported [arithmetic operator](#expressions):\n\n```\nDefinition.  The binary operation + on ℕ is defined recursively such that\n  for all x, y : ℕ,\n\n  a.  x + 0 = x.\n  b.  x + S(y) = S(x + y).\n```\n\nA _direct definition_ defines a function non-recursively, using a single formula.  Currently the function must be a supported [relational operator](#propositions):\n\n```\nDefinition.  For all x, y : ℕ, x \u003C y iff there is some z : ℕ such that x + S(z) = y.\n```\n\n### Theorems\n\nA natural-language theorem is introduced by the capitalized keyword `Theorem` (as distinguished from lowercase `theorem`, which begins a theorem in native Lean syntax).  Every theorem must have a __name__, which may appear either immediately after the word `Theorem`, or in brackets after the theorem statement.  Thus, these two declarations are equivalent:\n\n```\nTheorem ℕ.succ_ne_self.  For all x : ℕ, S(x) ≠ x.\n\nTheorem.  For all x : ℕ, S(x) ≠ x.  [ℕ.succ_ne_self]\n```\n\nI generally find the second style above to be more readable.\n\nA theorem's name must be a valid Lean identifier and is its actual name in Lean.  Additionally a theorem may optionally have a __long name__, which may be any string and appears in quotes:\n\n```\nTheorem \"Associativity of Addition\".  For all x, y, z: ℕ,\n\n  x + (y + z) = (x + y) + z.  [ℕ.add_assoc]\n```\n\n(At the moment a long theorem name is just documentation; it's not possible to refer to it as a reason in a proof step.)\n\nA theorem name in brackets may optionally be followed by a Lean attribute to attach to the theorem:\n\n```\nTheorem.  For all x : ℕ, 0 + x = x.  [ℕ.zero_add: @simp]\n```\n\nA theorem may or may not be followed by a __proof__.  If a proof is not present, Natural Lean will attempt to prove the theorem using the [default tactic](#tactics).  If a proof is present, it appears after the text `Proof.`:\n\n```\nTheorem.  For all x : ℕ, x \u003C S(x).  [ℕ.lt_succ]\n\nProof.  Let x : ℕ.  x + S(0) = S(x).  Therefore x \u003C S(x).\n```\n\nThe section [Proofs](#proofs) below describes the structure of proofs.\n\nA theorem may optionally being with a `Let` declaration introducing one or more quantified variables, so the preceding theorem may alternatively be written as\n\n```\nTheorem.  Let x : ℕ.  x \u003C S(x).  [ℕ.lt_succ]\n\nProof.  x + S(0) = S(x).  Therefore x \u003C S(x).\n```\n\nA `Let` declaration of this nature is automatically included at the beginning of a proof, unless the proof already begins with a `Let` declaration.\n#### Theorem groups\n\nSeveral theorems may appear together in a single __theorem group__:\n\n```\nTheorem.  Let x, y, z : ℕ.\n\n  a. x ≤ x.  [ℕ.le_refl]\n  b. If x \u003C y and y ≤ z then x \u003C z.  [ℕ.lt_of_lt_of_le]\n  c. If x ≤ y and y \u003C z then x \u003C z.  [ℕ.lt_of_le_of_le]\n\nProof.\n\n  b. Suppose that x \u003C y ≤ z.  We know that y = z or y \u003C z.  If y = z, then x \u003C z.\n    If y \u003C z, then x \u003C z by ℕ.lt_trans.\n\n  c. Suppose that x ≤ y and y \u003C z.  We know that x = y or x \u003C y.  If x = y,\n    then y \u003C z.  If x \u003C y, then x \u003C z by ℕ.lt_trans.\n```\n\nIn a theorem group, each theorem must have a __label__, such as \"a\", \"b\" or \"c\" above.  The theorem group may have an associated `Proof` section containing labelled proofs for the theorems in the group.  As in the example above, some theorems in the group might not have proofs.\n\nAs visible above, a theorem group may begin with a `Let` declaration that is shared by all theorems in the group.   Any free variables in each theorem's statement will automatically be universally quantified using the type in the `Let` declaration.  Thus, the theorem group above is equivalent to\n\n```\nTheorem.\n\n  a. For all x : ℕ, x ≤ x.  [ℕ.le_refl]\n  b. For all x, y, z : ℕ, if x \u003C y and y ≤ z then x \u003C z.  [ℕ.lt_of_lt_of_le]\n  c. For all x, y, z : ℕ, if x ≤ y and y \u003C z then x \u003C z.  [ℕ.lt_of_le_of_le]\n\nProof.\n  ...\n```\n\nA `Let` declaration at the top of a theorem group will automatically be included at the beginning of each proof in the group, unless that proof already begins with its own `Let` declaration. \n\n### Proofs\n\nA __proof__ consists either of the keyword `By` followed by a __reason__, or a series of __proof steps__.\n\nA reason may be any of the following:\n\n- One or more theorem names, separated by `and`, e.g.\n\n  `By ℕ.add_assoc and ℕ.succ_ne_self.`\n\n- The keyword `induction`.\n- An arbitrary Lean tactic in brackets, e.g.\n\n  `By [simp +arith]`.\n\nA proof step may be any of the following:\n\n- An __assertion__ states a fact.  It may be preceded by a word such as `So`, `Now`, `Hence` or `Clearly`, and may optionally include a reason introduced by the `by` keyword.  Examples:\n\n    ```\n    Clearly 0 ∈ B.\n    Hence by induction y ∈ B for all y: ℕ.\n    Then x \u003C z by ℕ.lt.\n    ```\n  (In addition to the reasons listed above, an assertion in a proof by induction may use the reason `by the inductive hypothesis`.)\n\n  If an assertion leads to a contradiction, it may say so:\n\n   ```\n   So x \u003C x, contradicting ℕ.lt_irrefl.\n   We have S(y) ≤ y, which is a contradiction to ℕ.lt_succ and ℕ.lt_trichotomy.\n   ```\n\n- A __let declaration__ introduces one or more universally quantified variables of a given type.  Examples:\n\n    ```\n    Let x, y, z : ℕ.\n    Let a : ℤ.\n    ```\n\n- A __let definition__ introduces a variable and gives it a value.  Examples:\n\n    ```\n    Let x = 0.\n    Let A = { z : ℕ | x + (y + z) = (x + y) + z }.\n    ```\n\n- An __assumption__ is expressed using the keyword `assume` or `suppose`.  Example:\n\n    ```\n    Assume that v ∈ A.\n    Suppose that z = 0 .\n    ```\n  \n  Natural Lean will infer an assumption's scope heuristically unless it appears at the beginning of an if/otherwise block (as described below).\n\nIn addition, the following are __compound steps__ that group proof steps together:\n\n- An __if/then__ block introduces an assumption whose scope is limited to a single sentence.  Example:\n\n   ```\n   If z = 0 then x = y, so x ≤ y.\n   ```\n\n   This is like\n\n   ```\n   Assume that z = 0.  Then x = y.  So x ≤ y.\n   ```\n\n   except that the first form above restricts the assumption `z = 0` to be active only through the assertion `x ≤ y`.\n\n- An __if/otherwise__ block allows a proof to consider two mutually exclusive possibilities.  It may have either of these forms:\n\n    ```\n    Assume A. (\u003Cproof_step>)+  Otherwise (\u003Cproof_step>)+  In either case B.\n\n    If A then \u003Cassertion>.  Otherwise (\u003Cproof_step>)+  In either case B.\n    ```\n\n  Here is an if/otherwise block expressed using each of the forms above, which are equivalent:\n\n    ```\n    Assume that x \u003C y.  Then there is some w : ℕ such that x + S(w) = y. \n      Otherwise x = y, so x + 0 = y.  In either case there is some z : ℕ such that\n      x + z = y.\n\n    If x \u003C y then there is some w : ℕ such that x + S(w) = y.  Otherwise x = y,\n      so x + 0 = y.  In either case there is some z : ℕ such that x + z = y.\n    ```\n\n- A __biconditional__ block proves a statement of the form `P iff Q`.  It has this form:\n\n    ```\n    Assume P.  (\u003Cproof_step>)+  Conversely, assume Q.  (\u003Cproof_step>)+\n    ```\n  \n  For example, here is a proof excerpt that proves that `x \u003C S(x) iff x \u003C S(y)`:\n\n  ```\n  Assume that x \u003C S(y).  If x > y then y \u003C x \u003C S(y), which is a contradiction\n  to ℕ.discrete.  So by ℕ.lt_trichotomy we have x ≤ y.\n\n  Conversely, assume that x ≤ y.  If x ≥ S(y) then by ℕ.le_trans we deduce that\n  S(y) ≤ y, which is a contradiction to ℕ.lt_succ.  So it must be that x \u003C S(y).\n  ```\n\n- A __cases__ block allows a proof to consider several mutually exclusive possibilities:\n\n  ```\n  Case 1: v \u003C y.  Then v + S(z) = y for some z : ℕ.  By ℕ.is_zero_or_succ either\n    z = 0, or z = S(u) for some u : ℕ.  So S(v) \u003C y or S(v) = y.\n\n  Case 2: v = y.  Then S(v) = S(y) = y + S(0).  So y \u003C S(v).\n\n  Case 3: y \u003C v.  Then v = y + S(u) for some u : ℕ.  Hence\n\n      S(v) = S(y + S(u)) = y + S(S(u)).\n\n    Thus y \u003C S(v).\n\n  In all cases S(v) \u003C y or S(v) = y or y \u003C S(v). \n  ```\n\n#### Sequences of proof steps\n\nIn theory, you may write each proof step as a single sentence, with no extra words between steps:\n\n```\nLet z : ℕ.  Assume z ∈ A.  x + z = y + z implies x = y.\nAssume x + S(z) = y + S(z).  S(x + z) = S(y + z).  x + z = y + z.\nBy the inductive hypothesis x = y.  x + S(z) = y + S(z) implies x = y.\nS(z) ∈ A.\n```\n\nHowever this style feels wooden and unnatural, and is discouraged in Natural Lean.  Instead, you may place  filler words such as \"so\", \"then\", \"therefore\", \"hence\", \"thus\" and so on between steps.  Furthermore, you may group multiple steps into a single sentence, separated by the words \"and\" or \"so\".  For example, the proof steps above might be rewritten like this:\n\n```\nLet z : ℕ and assume z ∈ A.  Then x + z = y + z implies x = y.\nNow assume x + S(z) = y + S(z).  Then S(x + z) = S(y + z).\nTherefore x + z = y + z.  Hence by the inductive hypothesis x = y.\nThus we have shown that x + S(z) = y + S(z) implies x = y,\nso S(z) ∈ A.\n```\n\nThis sounds more like textbook mathematics, and illustrates the writing style for which Natural Lean is intended. \n\n### Propositions\n\nEach theorem asserts that a certain __proposition__ is true, and every assertion step in a proof also contains a proposition.  A proposition may have any of these forms:\n\n```\n\u003Cexpr> \u003Crel_op> \u003Cexpr>\n\u003Cprop> (,)? and \u003Cprop>\n(either)? \u003Cprop> (,)? or \u003Cprop>\n\u003Cprop> implies \u003Cprop>\n\u003Cprop> iff \u003Cprop>\nif \u003Cprop> then \u003Cprop>\nfor all (\u003Cvar>),+ : \u003Ctype> , \u003Cprop>\n\u003Cprop> for all (\u003Cvar>),+ : \u003Ctype>\nthere exists (some | no) (\u003Cvar>),+ : \u003Ctype> such that \u003Cprop>\n\u003Cprop> for some (\u003Cvar>),+ : \u003Ctype>\n(at least | at most | exactly) one of (\u003Cprop>),+ is true\n(this is | we have) a contradiction\n```\n\nAbove `\u003Cprop>` is a proposition and `\u003Crel_op>` indicates a relational operator such as `=`, `≠` or `\u003C`.   `\u003Cexpr>` and `\u003Ctype>` are expressions or types as described in the sections that follow.\n\nHere are some examples of propositions:\n\n```\nx = 0\nx + S(y) = S(x + y)\nx \u003C y and y \u003C z implies x \u003C z\nfor all x : ℕ, S(x) ≠ x\nz ∈ A for all z: ℕ\nthere exists some y : ℕ such that x = S(y)\ny = S(u) for some u : ℕ\nat least one of x \u003C y, x = y, y \u003C x is true\n```\n\nNatural Lean follows the usual precedence for Boolean operators:  `and` normally has the highest precedence, followed in turn by `or`, `implies` and `iff`.  For example, `x > 0 and y > 0 or z > 0` means `(x > 0 and y > 0) or z > 0`.  However, a comma before `and` or `or`will cause the operator to have a low precedence.  For example, `x > 0, and y > 0 or z > 0` means `x > 0 and (y > 0 or z > 0)`.\n#### Operator chains\n\nA proposition may contain __chained relational operators__: for example, `x \u003C y ≤ z = w` has the same meaning as `x \u003C y and y ≤ z and z = w`.  In an assertion, each step in a chain may optionally have a reason:\n\n```\nz = (x + S(u)) + S(v)\n  = x + (S(u) + S(v)) by ℕ.add_assoc\n  = x + S(u + S(v)) by ℕ.succ_add.\n```\n\n### Expressions\n\n__Expressions__ represent mathematical values.  In Natural Lean an expression has any of the following forms:\n\n```\n\u003Cnum>\n\u003Cvar>\n\u003Cexpr> \u003Cexpr>      -- implicit multiplication\n\u003Cexpr> \u003Cop> \u003Cexpr>\n\u003Cexpr> ( \u003Cexpr> )  -- function call or multiplication\n( \u003Cexpr> )\n{ \u003Cvar> : \u003Ctype> | \u003Cprop> }\n```\n\nAbove, `\u003Cnum>` is a natural number constant and `\u003Cop>` is an arithmetic operator.  At the moment Natural Lean includes only a small fixed set of these operators: the `+`,  `·` and `^` operators, plus `×` which is a synonym for `·`. (I hope to extend the system before long so that all operators predefined in a Lean theory will also be available in Natural Lean.)\n\nHere are some examples of expressions:\n\n```\n0\ny\nx + (y + z)\nS(x + y)\na(b + c)\nac + bc\n{ z : ℕ | x + (y + z) = (x + y) + z }\n```\n\nImplicit multiplication is supported: `xy` with no parentheses means `x · y`.  Note that Natural Lean uses the traditional function call syntax `f(x)`, which is different from `f x` as found in native Lean code.  An expression of the form `a(b)` is potentially ambiguous: it may represent either a multiplication or a function call.  Natural Lean resolves this ambiguity based on the type of `a`: if it is a function, then `a(b)` is considered to be a function call, otherwise a multiplication.\n\nAny Lean keyword such as `def` cannot be used as an implicit product in Natural Lean.  So if you want to compute the product of variables `d`, `e`, and `f`, you can write e.g. `d · e · f` or `(de)f`, but not `def`.  Note that `at` is also a Lean keyword, so you must write `a · t` for the product of `a` and `t`.  (I hope to remove this limitation at some future point.)\n\n\nUnicode superscript digits and letters are supported, so you may write e.g. `x²` in place of `x^2`, or `xʸ` in place of `x^y`.  A superscripted expression may include the  `+` operator, so `xⁱ⁺ʲ` is the same as `x ^ (i + j)`.\n\n### Types\n\nAt the moment any type in Natural Lean must be either a simple type such as `Nat`, or a function type such as `Nat → Nat → Nat`.\nI plan to add other types such as product types soon.\n\n### Natural names\n\nIn Natural Lean, any simple type such as `Nat` or `Int` may have a __natural name__ such as \"natural number\" or \"integer\".  You may refer to a type either by its Lean name or its natural name.  For example, the following statements are equivalent:\n\n```\nFor all x : Nat, x \u003C x + 1.\n\nFor all natural numbers x, x \u003C x + 1.\n```\n\nYou can use an attribute to assign a natural name to a type that already exists in Lean:\n\n```\nattribute [natural_name \"natural number\"] Nat\nattribute [natural_name \"integer\"] Int\n```\n\nIn fact the preceding two attributes are predefined in Natural Lean, so you don't need to write them.\n\nA natural name must consist of only one or two words, each of which must be at least two letters long (to help distinguish them from variable names).\n\nWhen you define a new type in Natural Lean, you may give it a natural name as well as a Lean name:\n\n```\nDefinition.  The type ℕ (the natural numbers) is defined inductively\n  with constructors 0 : ℕ and S : ℕ → ℕ.\n```\n\n\n\nThis particular definition redefines the name \"natural number\" so that it refers to the inductive type that it is defining, rather than Lean's built-in `Nat` type.\n\n### Tactics\n\nWhen an assertion does not contain a reason, or when a theorem does not include a proof at all, Natural Lean will attempt to prove the assertion or theorem using a tactic named `default` which tries each of `trivial`, `grind` and `aesop` in turn.  In the future I intend to make the default tactic configurable by any development in Natural Lean, but for the moment it is fixed.\n\nAs described above, an assertion or theorem may have a reason indicating one or more named theorems:\n\n```\nBut x + S(z) ≠ x by ℕ.not_succ_add and ℕ.add_comm.\n```\n\nIn this situation Natural Lean will invoke the tactic `default_apply` with the given theorem names  `default_apply` is a tactic that calls each of `apply_rules`, `grind` and `aesop` in turn, passing the given theorems as arguments.  (I also intend to make this tactic configurable in the future.)\n\n### Visual Studio Code integration\n\nYou may notice that Visual Studio Code doesn't display a double checkmark beside natural-language theorems that have been proven.  That's due to a [bug](https://github.com/leanprover/lean4/issues/15044) in Lean.  I have submitted a [pull request](https://github.com/leanprover/lean4/pull/15045) that will fix it, so hopefully that will land soon.\n\nWhen you first open a file with Natural Lean code, Visual Studio Code will display its default syntax highlighting, which colors many words in natural-language text:\n\n![default highlighting](images/default_highlighting.png)\n\nIn my opinion this is not easy to read.  As soon as you make any edit to the file, Natural Lean's own syntax highlighting will appear instead:\n\n![natural highlighting](images/natural_highlighting.png)\n\nInstead of editing the file, you can alternatively produce the natural highlighting by switching to any other tab in the same editor pane, then switching back.\n\nIt would be nicer if the natural highlighting appeared as soon as you open the file, however a [bug in Lean](https://github.com/leanprover/lean4/issues/15118) currently prevents this from happening.\n\nNatural Lean's syntax highlighting shows natural-language text using the token type `operator`, which by default appears as pure black (in a light theme) or pure white (in a dark theme).  In my opinion this is a bit too strong.  To dim the text a bit, include this in your `settings.json` file:\n\n```\n    \"editor.semanticTokenColorCustomizations\": {\n        \"[*Light*]\": {\n            \"rules\": {\n                \"operator:lean4\": \"#3B3B3B\"\n            }\n        }, \"[*Dark*]\": {\n            \"rules\": {\n                \"operator:lean4\": \"#C4C4C4\"\n            }\n        }\n    },\n```\n\n(It would be nicer to have a separate token type such as `natural` for natural-language text, however Lean does not allow a library to add custom token types, so we fall back on `operator` instead.)\n\nWhen working with Natural Lean, you might even want to configure Visual Studio Code to display your text in a variable-width font, e.g. like this:\n\n```\n\"[lean4]\": {\n    \"editor.fontFamily\": \"'DejaVu Sans', Sans\",\n    \"editor.fontSize\": 13,\n},\n```\n\nIn my opinion this is the nicest way to view and edit natural-language mathematics.  However the setting above will also cause all code in any Lean file to be displayed in variable width, which may not be ideal.\n\n### Hints and tips\n\n#### Proving steps\n\nThe `try?` tactic is very useful.  If a proof step fails, try adding `by [try?]`to that step.  If that succeeds, the information in the InfoView may reveal which theorem(s) you will need to use to prove the step without `try?`.  For example, if the InfoView shows\n\n  ```\n  Try these:\n    [apply] grind only [Nat.eq_one_of_mul_eq_one_left]\n    [apply] grind => instantiate only [Nat.eq_one_of_mul_eq_one_left]\n  ```\n\nthen you should be able to prove the step by writing `by Nat.eq_one_of_mul_eq_one_left`, since Natural Lean's `default_apply` tactic will call `grind`.\n\nOn the other hand, `try?` may report a large number of theorems to use:\n\n```\nTry these:\n  [apply] grind only [instLEℕ.le_spec_1, ℕ.add_right_cancel, ℕ.lt_of_add_lt_add_right,\n  ℕ.lt_trichotomy, ℕ.add_lt_add_right, ℕ.lt_trans, #187d]\n```\n\nThen  you might be able to prove the step by writing `by` followed by a list of all of those theorems .  However, that seems awkward: the whole point of Natural Lean is that proofs should be readable, and it may not be clear how the theorems in a list such as this can be combined to prove the step.  So in this situation it may be better to break the step into smaller steps, producing a readable proof.\n\n#### Grammar\n\nNatural Lean is currently quite lax about plurals, articles, and capitalization, so at the moment you may be able to get away with writing ungrammatical English such as \"Let a and b be natural number\".  I plan to check grammar more strictly in the future.\n\n#### Debugging\n\nIf you would like to see the Lean code that is generated from any definition or theorem in Natural Lean, write `set_option trace.natural.proof true in` immediately before the definition or theorem.  The Lean code will be visible in the InfoView window in Visual Studio Code.\n",1789237286162]