Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lean4/en] Documentation for Lean 4. #4893

Merged
merged 5 commits into from
May 13, 2024
Merged

[lean4/en] Documentation for Lean 4. #4893

merged 5 commits into from
May 13, 2024

Conversation

balu
Copy link
Contributor

@balu balu commented Apr 16, 2024

  • I solemnly swear that this is all original content of which I am the original author
  • Pull request title is prepended with [language/lang-code] (example [python/fr-fr] or [java/en])
  • Pull request touches only one file (or a set of logically related files with similar changes made)
  • Content changes are aimed at intermediate to experienced programmers (this is a poor format for explaining fundamental programming concepts)
  • If you've changed any part of the YAML Frontmatter, make sure it is formatted according to CONTRIBUTING.md
  • Yes, I have double-checked quotes and field names!

This documentation contains more comments than the usual tutorials in this repository. Most of it explains theorem proving and not fundamental programming concepts. I think it is still aimed at intermediate to experienced programmers. Please let me know if I should change it.

Using this we can prove `1 = 1` as follows.
-/

def one_eq_one : 1 = 1 := Eq.refl 1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style-wise, every theorem should be defined as such; i.e. theorem one_eq_one : 1 = 1 := ....
One can of course view these as noncomputable defs, but that's out of the scope of this intro.

The following will fail because both sides are not "obviously equal".
-/

/- def pf : 2^9-2^8 = 2^8 := Eq.refl (2^8) -/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'obviously equal' here is definitionally equal; it will work just fine if you feed it the side that reduces.
i.e. theorem pf : 2^9-2^8 = 2^8 := Eq.refl (2 ^ 9 - 2 ^ 8), or theorem pf : 2^9-2^8 = 2^8 := rfl (which constructs the former term).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed this theorem altogether. You are right, this theorem does not make sense to me after reading your comments.

let p2 : 2^9-2^8 = 2^8 * 2 - 2^8 := sorry
let p3 : 2^8 * 2 - 2^8 = 2^8 * (2-1) := sorry
let p4 : 2^8 * (2-1) = 2^8 := sorry
Eq.trans (Eq.trans p2 p3) p4
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the above, either do this symbolically where this proof is needed or use rfl, or quite canonically, decide or mathlib's norm_num.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use have instead of let, the data is in Prop which is proof-irrelevant.

let p4 : 2^8 * (2 - 1) = 2^8 :=
Nat.mul_one (2^8)
Eq.trans (Eq.trans p2 p3) p4

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Eq.trans (Eq.trans p2 p3) p4

/-
For individual steps, we use proofs already available in Lean. For example:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth noting we're at the liberty to prove whatever it is we so desire.

specialize h e
obtain ⟨h1, _⟩ := h
have h' := identity e'
obtain ⟨_, h2⟩ := h'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have we started using obtain instead of the let up until now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are obtain and let interchangeable?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're not. obtain is a have + full expressivity of what you call 'rcases patterns'. let is a proof-relevant binder that just happens to be able to deconstruct some simple patterns.

E.g. the former can do things like:

  obtain h₁ | h₂ := X```
  
I would say `obtain` is almost a superset but that's somewhat misleading because `let's` are meant to be used for a different purpose + there's the distinction of whether they keep the data on their rhs around.

So, just think of them as two different features. `obtain` allows you to inspect terms, `let` allows you to introduce new terms.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I have replaced all let with have in proofs. I think in proofs this is the right thing to do due to proof irrelevance as you mentioned.

Thanks for your comments. They have been very helpful.

obtain ⟨h1, _⟩ := h
have h' := identity e'
obtain ⟨_, h2⟩ := h'
apply Eq.trans (Eq.symm h2) h1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably say exact now that you introduced it above.


/-
Mutually recursive definitions have to be carefully constructed. In particular,
the hypotheses when recursing should imply well-foundedness.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is misleading. Every definition in Lean has to be well-founded, regardless of whether it's mutually defined.

/-
Programming algorithms in Lean is harder.

This is because we have to convince Lean of termination. Here's a simple
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not true. Lean accepts partial definitions that can be computed with just fine; just can't be unfolded to reason with.

label the test `n ≤ k` by `h` so that the falsification of this proposition can
be used by `omega` later to conclude that `n > k`.

The tactic `omega` is a general-purpose solver for equalities and inequalities.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also not true. omega is a specific-purpose decision procedure for deciding problems in presburger arithmetic.

bkomarath added 2 commits April 29, 2024 11:40
  - Remove useless theorem `2^9-2^8 = 2^8`.
  - Rewrite misleading comments.
  - Use `theorem` and `have` appropriately instead of `def` and `let`.
@verhovsky
Copy link
Collaborator

@Ferinko I'm merging this. If there's other issues or parts of your review that weren't addressed or any other things you want to add, it would be nice if you submitted a pull request.

@verhovsky verhovsky merged commit 7b4a50a into adambard:master May 13, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants