Zulip Chat Archive

Stream: lean4

Topic: cases on expressions that evaluate to inductive types


Paige Thomas (Jul 06 2025 at 04:21):

If I have an inductive type, say

inductive Formula_ : Type
  | false_ : Formula_
  | true_ : Formula_
  | atom_ : String  Formula_
  | not_ : Formula_  Formula_
  | and_ : Formula_  Formula_  Formula_
  | or_ : Formula_  Formula_  Formula_
  | imp_ : Formula_  Formula_  Formula_
  | iff_ : Formula_  Formula_  Formula_

and I have an expression e that evaluates to a type Formula_, and a hypothesis h : e = not_ e, is there a tactic that will immediately prove that this is a contradiction? It seems that I need to do something like set F := e before cases h will work.

Chase Norman (Jul 06 2025 at 05:36):

Canonical can solve this outright, but I've taken the liberty of using induction to handle the absurd cases:

example : e  Formula_.not_ e := by
  -- canonical
  induction e with
  | not_ e a_ih => exact fun a  a_ih (by simpa only [Formula_.not_.injEq] using a)
  | _ => exact fun a  by simpa only [reduceCtorEq] using a

Paige Thomas (Jul 06 2025 at 05:57):

Hmm. I think maybe I didn't communicate what I meant very well. I can prove that the hypothesis is a contradiction by using set to replace the expression by a single variable name and then uses cases on the hypothesis, I was just wondering why it is necessary to use set first.

Paige Thomas (Jul 06 2025 at 05:59):

For example, I have the hypothesis contra : replace_atom_all_rec σ phi = replace_atom_all_rec σ phi.not_. If I do set H := replace_atom_all_rec σ phi and then cases contra it solves the goal, but I'm not sure I understand why I need to do the set first and not just use cases contra.

Edward van de Meent (Jul 06 2025 at 10:28):

you can do this:

example (e : Formula_) (he : e = .not_ e) : False := by
  have : sizeOf e = sizeOf (Formula_.not_ e) := congr(sizeOf $he)
  simp at this

Edward van de Meent (Jul 06 2025 at 10:29):

the main idea here is that he leads to an infinite regression, however since values of inductives have a definable "size", this would lead to some natural number being its own successor

Edward van de Meent (Jul 06 2025 at 10:30):

or even a one-liner proof: simpa using congr(sizeOf $he)

Edward van de Meent (Jul 06 2025 at 10:31):

you do need Mathlib.Tactic for this, specifically the congr quotation

Robin Arnez (Jul 06 2025 at 12:48):

Use cases he. Under the hood it will do the same thing @Edward van de Meent recommended

Edward van de Meent (Jul 06 2025 at 12:50):

i was under the impression that OP tried that and it didn't work? but indeed, it looks like that also works...

Robin Arnez (Jul 06 2025 at 12:53):

Oh I guess the question is rather <complex expression> = .not_ <complex expression> not working?

Paige Thomas (Jul 07 2025 at 02:59):

Yes, it is that cases h does not work on h: <complex expression> = .not_ <complex expression>. For some reason I have to do something like set F := <complex expression> before cases h.

Kyle Miller (Jul 07 2025 at 03:36):

docs#Lean.MVarId.acyclic is what is responsible for the way cases handles acyclicity, and in Lean.MVarId.isTarget you can see that it looks specifically for a free variable on one side and that free variable appearing in the other side.

That explains exactly why you need to use set (or generalize) as a first step.

I imagine the reason it was coded this way is that it's assumed that it's only supposed to support constructor applications, so the other reasoning in docs#Lean.Meta.unifyEq? will reduce to the case of a free variable on one side in that case.

I wonder how far dependent elimination could get in more cases if instead of an acyclicity prover it was a general sizeOf-based prover. Then, for example, it might be able to make progress on List.append indexes, etc.

Paige Thomas (Jul 07 2025 at 04:03):

Hmm. Ok. I might have to come back to trying to understand that in its entirety at a later time. Thank you.


Last updated: Dec 20 2025 at 21:32 UTC