Fixes typo "reflexivitiy" to "reflexivity", and changes exact Eq.rfl to
exact rfl, since Eq.rfl does not exist.
(I got something confused wrt the bot message on #4367 and accidentally
closed that one, so making this one instead, which I think satisfies the
requirements it wanted.)
---------
Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
this is the simplest of the constructions to be ported from C++ to Lean,
so I’ll PR this one first.
This begins to put each construction into its own file, as it was the
case with C++.
For validation I developed this in a separate repository at
https://github.com/nomeata/lean-constructions/tree/fad715e
and checked that all `.recOn` declarations found in Lean and Mathlib are
identical (per `==`) to the ones produced by the C code.
This is the groundwork for a tactic index in generated documentation, as
there was in Lean 3. There are a few challenges to getting this to work
well in Lean 4:
* There's no natural notion of *tactic identity* - a tactic may be
specified by multiple syntax rules (e.g. the pattern-matching version of
`intro` is specified apart from the default version, but both are the
same from a user perspective)
* There's no natural notion of *tactic name* - here, we take the
pragmatic choice of using the first keyword atom in the tactic's syntax
specification, but this may need to be overridable someday.
* Tactics are extensible, but we don't want to allow arbitrary imports
to clobber existing tactic docstrings, which could become unpredictable
in practice.
For tactic identity, this PR introduces the notion of a *tactic
alternative*, which is a `syntax` specification that is really "the same
as" an existing tactic, but needs to be separate for technical reasons.
This provides a notion of tactic identity, which we can use as the basis
of a tactic index in generated documentation. Alternative forms of
tactics are specified using a new `@[tactic_alt IDENT]` attribute,
applied to the new tactic syntax. It is an error to declare a tactic
syntax rule to be an alternative of another one that is itself an
alternative. Documentation hovers now take alternatives into account,
and display the docs for the canonical name.
*Tactic tags*, created with the `register_tactic_tag` command, specify
tags that may be applied to tactics. This is intended to be used by
doc-gen and Verso. Tags may be applied using the `@[tactic_tag TAG1 TAG2
...]` attribute on a canonical tactic parser, which may be used in any
module to facilitate downstream projects introducing tags that apply to
pre-existing tactics. Tags may not be removed, but it's fine to
redundantly add them. The collection of tags, and the tactics to which
they're applied, can be seen using the `#print tactic tags` command.
*Extension documentation* provides a structured way to document
extensions to tactics. The resulting documentation is gathered into a
bulleted list at the bottom of the tactic's docstring. Extensions are
added using the `tactic_extension TAC` command. This can be used when
adding new interpretations of a tactic via `macro_rules`, when extending
some table or search index used by the tactic, or in any other way. It
is a command to facilitate its flexible use with various extension
mechanisms.
The linters in Batteries can be used to spot mistakes in Lean. See the
message on
[Zulip](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Go-to-def.20on.20typeclass.20fields.20and.20type-dependent.20notation/near/442613564).
These are the different linters with errors:
- unusedArguments:
There are many unused instance arguments, especially a redundant `[Monad
m]` is very common
- checkUnivs:
There was a problem with universes in a definition in
`Init.Control.StateCps`. I fixed it by adding a `variable` statement for
the implicit arguments in the file.
- defLemma:
many proofs are written as `def` instead of `theorem`, most notably
`rfl`. Because `rfl` is used as a match pattern, it must be a def. Is
this desirable?
The keyword `abbrev` is sometimes used for an alias of a theorem, which
also results in a def. I would want to replace it with the `alias`
keyword to fix this, but it isn't available.
- dupNamespace:
I fixed some of these, but left `Tactic.Tactic` and `Parser.Parser` as
they are as these seem intended.
- unusedHaveSuffices:
I cleaned up a few proofs with unused `have` or `suffices`
- explicitVarsOfIff:
I didn't fix any of these, because that would be a breaking change.
- simpNF:
I didn't fix any of these, because I think that requires knowing the
intended simplification order.
This is not the most exciting place to start, but I started here to:
* pick a function with little development in Batteries and Mathlib, so I
wouldn't have conflicts
* that is easy!
* to see how much effort it is to get fairly complete coverage
* and to set up some infrastructure to be used later, i.e.
`tests/lean/run/list_simp.lean`
This assigns priorities to the equational lemmas so that more specific
ones
are tried first before a possible catch-all with possible
side-conditions.
We assign very low priorities to match the simplifiers behavior when
unfolding
a definition, which happens in `simpLoop`’ `visitPreContinue` after
applying
rewrite rules.
Definitions with more than 100 equational theorems will use priority 1
for all
but the last (a heuristic, not perfect).
fixes#4173, to some extent.
`Nat.succ_eq_add_one` and `Nat.pred_eq_sub_one` are now simp lemmas. For
theorems about `Nat.succ` or `Nat.pred` without corresponding theorem
for `+ 1` or `- 1`, this adds the corresponding theorem.
This PR neither adds nor removes material, but improves the organization
of `Init/Data/List/*`.
These files are essentially completely re-ordered, to ensure that
material is developed in a consistent order between `List.Basic`,
`List.Impl`, `List.BasicAux`, and `List.Lemmas`.
Everything is organised in subsections, and I've added some module docs.
This came up when watching new Lean users in a class situation. A number
of them were confused when they omitted a namespace on a constructor
name, and Lean treated the variable as a pattern that matches anything.
For example, this program is accepted but may not do what the user
thinks:
```
inductive Tree (α : Type) where
| leaf
| branch (left : Tree α) (val : α) (right : Tree α)
def depth : Tree α → Nat
| leaf => 0
```
Adding a `branch` case to `depth` results in a confusing message.
With this linter, Lean marks `leaf` with:
```
Local variable 'leaf' resembles constructor 'Tree.leaf' - write '.leaf' (with a dot) or 'Tree.leaf' to use the constructor.
note: this linter can be disabled with `set_option linter.constructorNameAsVariable false`
```
Additionally, the error message that occurs when invalid names are
applied in patterns now suggests similar names. This means that:
```
def length (list : List α) : Nat :=
match list with
| nil => 0
| cons x xs => length xs + 1
```
now results in the following warning on `nil`:
```
warning: Local variable 'nil' resembles constructor 'List.nil' - write '.nil' (with a dot) or 'List.nil' to use the constructor.
note: this linter can be disabled with `set_option linter.constructorNameAsVariable false`
```
and error on `cons`:
```
invalid pattern, constructor or constant marked with '[match_pattern]' expected
Suggestion: 'List.cons' is similar
```
The list of suggested constructors is generated before the type of the
pattern is known, so it's less accurate, but it truncates the list to
ten elements to avoid being overwhelming. This mostly comes up with
`mk`.
We recently discovered inconsistencies in Mathlib and Std over the
ordering of the arguments for `==`.
The most common usage puts the "more variable" term on the LHS, and the
"more constant" term on the RHS, however there are plenty of exceptions,
and they cause unnecessary pain when switching (particularly, sometimes
requiring otherwise unneeded `LawfulBEq` hypotheses).
This convention is consistent with the (obvious) preference for `x == 0`
over `0 == x` when one term is a literal.
We recently updated Std to use this convention
https://github.com/leanprover/std4/pull/430
This PR changes the two major places in Lean that use the opposite
convention, and adds a suggestion to the docstring for `BEq` about the
preferred convention.
The performance issue at #4413 is due to our `Fin.sub` definition.
```
def sub : Fin n → Fin n → Fin n
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a + (n - b)) % n, mlt h⟩
```
Thus, the following runs out of stack space
```
example (a : UInt64) : a - 1 = a :=
rfl
```
at the `isDefEq` test
```
(a.val.val + 18446744073709551615) % 18446744073709551616 =?= a.val.val
```
From the user's perspective, this timeout is unexpected since they are
using small numerals, and none of the other `Fin` basic operations (such
as `Fin.add` and `Fin.mul`) suffer from this problem.
This PR implements an inelegant solution for the performance issue. It
redefines `Fin.sub` as
```
def sub : Fin n → Fin n → Fin n
| ⟨a, h⟩, ⟨b, _⟩ => ⟨((n - b) + a) % n, mlt h⟩
```
This approach is unattractive because it relies on the fact that
`Nat.add` is defined using recursion on the second argument.
The impact on this repo was small, but we want to evaluate the impact on
Mathlib.
closes#4413
Before this commit, the `theorem` and `def` declarations had different
universe parameter orders.
For example, the following `theorem`:
```
theorem f (a : α) (f : α → β) : f a = f a := by
rfl
```
was elaborated as
```
theorem f.{u_2, u_1} : ∀ {α : Sort u_1} {β : Sort u_2} (a : α) (f : α → β), f a = f a :=
fun {α} {β} a f => Eq.refl (f a)
```
However, if we declare `f` as a `def`, the expected order is produced.
```
def f.{u_1, u_2} : ∀ {α : Sort u_1} {β : Sort u_2} (a : α) (f : α → β), f a = f a :=
fun {α} {β} a f => Eq.refl (f a)
```
This commit fixes this discrepancy.
@semorrison @jcommelin: This might be a disruptive change to Mathlib,
but it is better to fix the issue asap. I am surprised nobody has
complained about this issue before. I discovered it while trying to
reduce discrepancies between `theorem` and `def` elaboration.
so that the pretty-printed origin is clickable, and avoid the
unnecessary `@`.
Particularly nice is this fix:
```diff
/--
-info: [Meta.Tactic.simp.discharge] @bar discharge ✅
+info: [Meta.Tactic.simp.discharge] bar discharge ✅
autoParam T _auto✝
- [Meta.Tactic.simp.rewrite] { }:1000, T ==> True
-[Meta.Tactic.simp.rewrite] @bar:1000, U ==> True
+ [Meta.Tactic.simp.rewrite] T.mk:1000, T ==> True
+[Meta.Tactic.simp.rewrite] bar:1000, U ==> True
-/
```
this is an amendment to #4177, after @kmill pointed out an issue:
Users might expect that within a tactic combinator like `first`, `simp
[h]` fails if `h` does not exist. Therefore the behavior introduced in
PR #4177, which is really most useful in mormal interactive use of
`skip`, is restricted to when `recover := true`.
types like
```
inductive Many (α : Type u) where
| none : Many α
| more : α → (Unit → Many α) → Many α
```
have a `.brecOn` only supports motives producing `Type u`, but not `Sort
u`, but our induction principles produce `Prop`. So the previous
implementation of functional induction would fail for functions that
structurally recurse over such types.
We recognize this case now and, rather hazardously, replace `.brecOn`
with `.binductionOn` (and thus `.below ` with `.ibelow` and `PProd` with
`And`). This assumes that these definitions are highly analogous.
This also improves the error message when realizing a reserved name
fails with an exception, by prepending
```
Failed to realize constant {id}:
```
to the error message.
Fixes#4320
Remark: when splitting an `if-then-else` term, the subgoals now have
tags `isTrue` and `isFalse` instead of `inl` and `inr`.
closes#4313
---------
Co-authored-by: Mario Carneiro <di.gama@gmail.com>
this fixes a usability paper cut that just annoyed me. When editing a
larger simp proof, I usually want to see the goal state after the simp,
and this is what I see while the `simp` command is complete. But then,
when I start typing, and necessarily type incomplete lemma names, that
error makes `simp` do nothing again and I see the original goal state.
In fact, if a prefix of the simp theorem name I am typing is a valid
identifier, it jumps even more around.
With this PR, using `logException`, I still get the red squiggly lines
for the unknown identifer, but `simp` just ignores that argument and
still shows me the final goal. Much nicer.
I also demoted the message for `[-foo]` when `foo` isn’t `simp` to a
warning and gave it the correct `ref`.
See it in action here: (in the middle, when you suddenly see the
terminal,
I am switching lean versions.)
https://github.com/leanprover/lean4/assets/148037/8cb3c563-1354-4c2d-bcee-26dfa1005ae0
Extends Lean's incremental reporting and reuse between commands into
various steps inside declarations:
* headers and bodies of each (mutual) definition/theorem
* `theorem ... := by` for each contained tactic step, including
recursively inside supported combinators currently consisting of
* `·` (cdot), `case`, `next`
* `induction`, `cases`
* macros such as `next` unfolding to the above

*Incremental reuse* means not recomputing any such steps if they are not
affected by a document change. *Incremental reporting* includes the
parts seen in the recording above: the progress bar and messages. Other
language server features such as hover etc. are *not yet* supported
incrementally, i.e. they are shown only when the declaration has been
fully processed as before.
---------
Co-authored-by: Scott Morrison <scott.morrison@gmail.com>