Zulip Chat Archive
Stream: mathlib4
Topic: split_ifs
Dan Velleman (Jun 17 2024 at 16:25):
Can someone explain these examples:
import Mathlib.tactic
example (u : Nat) (h : u = u) : (if u = u then 0 else 1) = 0 := by
split_ifs
rfl
done
example (u : Nat) : (if u = u then 0 else 1) = 0 := by
have h : u = u := by rfl
split_ifs
rfl; rfl
done
In the first proof, after the split_ifs
the goal is 0 = 0
, and rfl
completes the proof. In the second proof, after split_ifs
there are two 0 = 0
goals, one with the additional hypothesis u = u
and one with the additional hypothesis ¬u = u
, so one needs two invocations of rfl
to complete the proof. Why the difference? The tactic state when split_ifs
is invoked appears to be the same in the two examples.
Jireh Loreaux (Jun 17 2024 at 16:44):
This seems like a missing withMainContext
in the implementation of split_ifs
to me, but I'm not super knowledgable about these things.
Jireh Loreaux (Jun 17 2024 at 16:44):
If you do show_term split_ifs
you can see the difference in what it produces.
Ruben Van de Velde (Jun 17 2024 at 16:46):
I think split_ifs looks for hypotheses that match the condition to avoid creating pointless subgoals
Jireh Loreaux (Jun 17 2024 at 16:47):
Right, but it should have found it in the second example, unless it didn't get the new context after the have
Ruben Van de Velde (Jun 17 2024 at 16:47):
Oh sorry, I missed the have
Jireh Loreaux (Jun 17 2024 at 17:36):
@David Renshaw since you ported this tactic, maybe you see the problem here? It's not immediately obvious to me.
Damiano Testa (Jun 17 2024 at 21:08):
Exceedingly often, weird tactic behaviour after have
is due to the presence of metadata introduced by the have
.
Damiano Testa (Jun 17 2024 at 21:15):
A quick look at the tactic makes me wonder whether there are a couple of whnfR
missing in getSplitCandidates
, around the getMainTarget
s, but I'm not at a computer to be able to check.
David Renshaw (Jun 18 2024 at 00:16):
This makes the behavior of the two versions match:
diff --git a/Mathlib/Tactic/SplitIfs.lean b/Mathlib/Tactic/SplitIfs.lean
index d41c91ddab..7a408e2004 100644
--- a/Mathlib/Tactic/SplitIfs.lean
+++ b/Mathlib/Tactic/SplitIfs.lean
@@ -102,9 +102,11 @@ private def getNextName (hNames: IO.Ref (List (TSyntax `Lean.binderIdent))) : Me
-/
private def valueKnown (cond : Expr) : TacticM Bool := do
let hTypes ← (((← getLCtx).getFVarIds.map mkFVar).mapM inferType : MetaM _)
- let hTypes := hTypes.toList
let not_cond := mkApp (mkConst `Not) cond
- return (hTypes.contains cond) || (hTypes.contains not_cond)
+ for ht in hTypes do
+ if ← isDefEq cond ht then return true
+ if ← isDefEq not_cond ht then return true
+ return false
David Renshaw (Jun 18 2024 at 00:17):
(and causes some breakage in mathlib)
David Renshaw (Jun 18 2024 at 00:31):
Just doing instantiateMVars
seems to works better...
David Renshaw (Jun 18 2024 at 00:39):
diff --git a/Mathlib/Tactic/SplitIfs.lean b/Mathlib/Tactic/SplitIfs.lean
index d41c91ddab..13d9944826 100644
--- a/Mathlib/Tactic/SplitIfs.lean
+++ b/Mathlib/Tactic/SplitIfs.lean
@@ -101,10 +101,12 @@ private def getNextName (hNames: IO.Ref (List (TSyntax `Lean.binderIdent))) : Me
/-- Returns `true` if the condition or its negation already appears as a hypothesis.
-/
private def valueKnown (cond : Expr) : TacticM Bool := do
- let hTypes ← (((← getLCtx).getFVarIds.map mkFVar).mapM inferType : MetaM _)
- let hTypes := hTypes.toList
let not_cond := mkApp (mkConst `Not) cond
- return (hTypes.contains cond) || (hTypes.contains not_cond)
+ for h in ← getLocalHyps do
+ let ty ← instantiateMVars (← inferType h)
+ if cond == ty then return true
+ if not_cond == ty then return true
+ return false
David Renshaw (Jun 18 2024 at 01:06):
I opened a pull request with a fix:
#13916
Last updated: May 02 2025 at 03:31 UTC