Zulip Chat Archive
Stream: new members
Topic: Variable inclusion defs vs. theorems
Klaus Gy (Aug 02 2025 at 01:44):
Why are variables used only in the proof automatically included in defs but not in theorems?
variable (n : Nat)
-- this gives an error, unknown identifier 'n'
theorem foo (m : Nat) : m = m :=
have : n = n := by rfl
rfl
-- this works fine
def foo' (m : Nat) : m = m :=
have : n = n := by rfl
rfl
Kyle Miller (Aug 02 2025 at 01:45):
The rule is that theorem includes variables based on what's mentioned in the theorem statement itself, but def includes variables based on the entire definition.
Klaus Gy (Aug 02 2025 at 01:45):
thanks! i was a bit surprised that its handled differently but i assume thats by design then :)
Kyle Miller (Aug 02 2025 at 01:46):
You can use the include n command to force the variable to be included in theorems
Kyle Miller (Aug 02 2025 at 01:46):
There are two practical reasons for this:
- Many tactics operate on the whole local context, and it can create artificial dependencies.
- This allows the proofs to be elaborated asynchronously.
Kyle Miller (Aug 02 2025 at 01:47):
Even basic tactics like induction/cases can cause variables to become included unnecessarily.
Kyle Miller (Aug 02 2025 at 01:48):
Example:
variable (n : Nat) (m : Fin n)
def ex : 0 ≤ n := by
induction n with
| zero => simp
| succ _ _ => simp
#check ex
/-
ex (n : Nat) (m : Fin n) : 0 ≤ n
-/
Klaus Gy (Aug 02 2025 at 01:50):
ah interesting, so the tactic can see m and could potentially use it, so its not auto discarded
Kyle Miller (Aug 02 2025 at 01:53):
and be sure to look at the local context to see why m is used here
Try changing it to (m : Fin 2). You should observe that it's not included.
Klaus Gy (Aug 02 2025 at 01:57):
ugh this is cursed, i dont fully understand, seems like the second placeholder assumes something with m, but only if m is available
Kyle Miller (Aug 02 2025 at 01:59):
In the first example, take a look how m changes, right before each simp.
Then, change it to (m : Fin 2), and look at the local contexts again.
What's the difference?
Klaus Gy (Aug 02 2025 at 02:03):
seems like induction works by simple induction P(n) => P(n + 1) if no fin n is available but if fin n is available it takes the more general form of (all x in fin n : P(n)) => P(n + 1)
Kyle Miller (Aug 02 2025 at 02:07):
In particular, since Fin n depends on the induction variable n, the tactic does revert m first, and then intro m in each case. It's the auto-generalizing feature. (The thing where you can use the generalizing clause to add in more variables to generalize.)
Kyle Miller (Aug 02 2025 at 02:08):
It needs to auto-generalize because n is reverted too, to apply the induction principle.
Kyle Miller (Aug 02 2025 at 02:12):
(Said another way, induction n basically starts off with revert n, and that's what causes the artificial dependency on m)
Klaus Gy (Aug 02 2025 at 02:14):
aah ok, thanks! what i wrote is bs, the more general induction principle is not what i wrote. yea makes much more sense now!
Last updated: Dec 20 2025 at 21:32 UTC