Zulip Chat Archive

Stream: lean4

Topic: Forall vs. if-then


Dan Velleman (Sep 17 2022 at 12:53):

Consider this example:

example :  (n : Nat), ¬  (x : Fin n), x  x := by

In the tactic state, the goal is shown as ℕ → ¬∃ x, x ≠ x. I have said before that I don't really like the algorithm that is used to distinguish between "forall" and "if-then," but in this case I'm really puzzled. I assumed that what was being used was Lean.Expr.isArrow, which checks to see if the body of the forallE has loose bound variables. Well, in this case the body does have a loose bound variable, namely the reference to n in Fin n. So why is this displayed using an arrow rather than a universal quantifier?

Gabriel Ebner (Sep 17 2022 at 13:24):

This is actually a pretty-printing bug... is always non-dependent, while the specific here is dependent.

Gabriel Ebner (Sep 17 2022 at 13:25):

Please file an issue.

Gabriel Ebner (Sep 17 2022 at 13:25):

The following would be a valid use of by the pretty-printer though:

#check  n : Nat, ¬∃ x : Nat, x  x

Gabriel Ebner (Sep 17 2022 at 13:26):

Ultimately this boils down to the underlying type theory; both implication and forall are represented as Expr.forallE. So the pretty-printer needs to make a choice whether to show the .forallE as an implication or a forall.

Dan Velleman (Sep 17 2022 at 15:13):

OK, I'll file an issue.
Yes, I understand that implication and forall are both represented as forallE. In my opinion, the pretty-printer algorithm should be changed. For an expression forallE name type body binderinfo that has type Prop, I think that if the type of type is not Prop then, even if body has no loose bvars, the expression should be displayed with a universal quantifier. In logic, it is not uncommon to have "vacuous quantifiers" like ∀ x : Nat, p. I understand that, to Lean, this is the same as Nat → p, but that's not how any mathematician would write it. For expressions of other types, the current algorithm makes sense. But if an expression has type Prop, then in my opinion it should be displayed so that it looks like a proposition. And that means the arrow should mean "implies", and therefore it should only be used if what's on the left is a proposition.

Kevin Buzzard (Sep 17 2022 at 17:07):

+1 for "Nat -> p looks weird to mathematicians"

Kevin Buzzard (Sep 17 2022 at 17:08):

On the other hand, it would be a bit weird to have a nat and then a prop which didn't depend on it ...

Kyle Miller (Sep 17 2022 at 17:52):

@Kevin Buzzard Sometimes these non-dependent foralls arise incidentally to rewrites (for example, if you have ∀ (n : ℕ), 1 ≤ f n and make use of ∀ (n : ℕ), f n = 37). I imagine you've had students become confused when their foralls turn into functions. There at least have been occasional questions on #new members about this.

Dan Velleman (Sep 19 2022 at 15:17):

I agree with @Kyle Miller that non-dependent foralls arise naturally in math. They also arise in formal logic. For example, there is a rule of logic that says that forall distributes over and: ∀ x, P ∧ Q is equivalent to (∀ x, P) ∧ (∀ x, Q). One would want to be able to apply this rule even in cases in which P is a statement about x but Q doesn't mention x. It would certainly be awkward to have separate versions of the rule depending on whether both P and Q mention x or only one of them does.

Here's a related point. Consider this example:

example (p1 : Nat  Type) (p2 : Nat  Prop) (h1 :  n : Nat, p1 n) (h2 :  n : Nat, p2 n) : True := by

In the tactic state, the type of h1 is displayed as (n : ℕ) → p1 n, and the type of h2 is ∀ (n : ℕ), p2 n. So it appears that there is a precedent for displaying expressions of type Prop differently from expressions of other types. The difference here makes sense to me: h2 is best thought of as a universally quantified statement, but h1 is best thought of as a function type. I think a similar principle applies to the case of ∀ n : Nat, p. If p is a proposition, then this is best thought of as a universally quantified statement (even though p doesn't refer to n), but if p is not a proposition then it makes sense to think of the expression as representing the type Nat → p.

Would there be a down side to making this change?

Kyle Miller (Sep 19 2022 at 18:13):

@Dan Velleman A couple days ago I experimented with making the change for Lean 3, and it was relatively straightforward. There didn't seem to be any downsides that surfaced through the test suite. (I just uploaded it: lean#770, and look at in particular pp_forall.lean for some tests.)


Last updated: Dec 20 2023 at 11:08 UTC