Zulip Chat Archive
Stream: new members
Topic: Modify a hypothesis referenced by `classical.some`
Patrick Johnson (Dec 07 2021 at 07:53):
MWE:
import tactic
open classical
example (h : ∃ (x : ℕ), (x = 0) = true) : some h = 0 := begin
simp_rw eq_true at h,
sorry,
end
The simp_rw
tactic creates a new premise instead of updating the existing premise h
. I guess that's because the goal references h
. Working backwards is possible:
example (h : ∃ (x : ℕ), (x = 0) = true) : some h = 0 := begin
rw ←@eq_true (some h = 0),
apply some_spec h,
end
But if the goal is more complicated, it is intractable. How to deal with this situation?
Kyle Miller (Dec 07 2021 at 08:02):
revert
and generalize
can be useful:
example (h : ∃ (x : ℕ), (x = 0) = true) : some h = 0 := begin
have := some_spec h,
revert this,
generalize : some h = n,
simp,
end
Kyle Miller (Dec 07 2021 at 08:05):
The idea is to put everything into the goal that has some kind of dependence on some value (via revert
), and then you can generalize
that value out of everything simultaneously.
Marcus Rossel (Dec 07 2021 at 08:06):
I recall the generalize_proofs tactic also being useful for these kinds of problems.
Kyle Miller (Dec 07 2021 at 08:14):
It's helpful to know roughly how rewriting actually works in Lean. It needs to create the motive for eq.rec
, which is sort of an expression with holes, and then given this motive and a proof that a = b
, what eq.rec
gives you is that plugging in a
into all the holes is equal to plugging in b
into all the holes.
When you rw h
where h : a = b
, then the tactic creates a motive from the goal by looking for all the a
's and turning them into holes. When you rw h at h'
, then it basically has to revert h'
, do the rewrite (but restricting its search for a
's inside the h'
part of the goal), and then intro h'
. If h
depends on h'
, then the revert would fail, and instead h'
is duplicated first. At least, this is my understanding.
Kyle Miller (Dec 07 2021 at 08:19):
So, said another way, the idea with using revert
and generalize
is to more carefully control how rw h at h'
operates -- you can rewrite the goal and multiple hypotheses simultaneously this way.
Patrick Johnson (Dec 07 2021 at 08:24):
Thanks. But it doesn't work if the goal also contains some_spec
:
example
(h : ∃ (x : ℕ), (x = 0) = true) :
some h = 0 ∧ some_spec h = some_spec h :=
begin
have h₁ := some_spec h,
revert h₁,
generalize : some h = n,
simp,
end
Produces error:
generalize tactic failed, result is not type correct
nested exception message:
check failed, application type mismatch
[check] application type mismatch at
eq _
argument type
(λ (x : ℕ), x = 0 = true) (some h)
expected type
n = 0 = true
Of course in this lemma we can use split, but I am talking in general.
Kyle Miller (Dec 07 2021 at 08:26):
example
(h : ∃ (x : ℕ), (x = 0) = true) :
some h = 0 ∧ some_spec h = some_spec h :=
begin
generalize_proofs h',
have h₁ := some_spec h,
revert h₁,
simp,
end
Kyle Miller (Dec 07 2021 at 08:35):
The problem is that some_spec h
contains some h
in its type, and it's not possible to create a motive in this situation. It's possible if you first remove some_spec h
from the expression, since then it can no longer require some h
literally being there.
Eric Rodriguez (Dec 07 2021 at 08:42):
"motive" = "expression with metavariables", right? how do the dreaded "motive is not type-correct" errors fit into this?
Johan Commelin (Dec 07 2021 at 08:57):
I have no idea what a motive is precisely. My mental model is that it's the combination (term_expr, type_expr)
. When that error shows up, something doesn't typecheck or is not a well-formed formula in some sense.
Kyle Miller (Dec 07 2021 at 08:59):
I still find "motive not type correct" to be somewhat mysterious, but I think many cases are related to my last comment. It can happen when the holes punched out are actually implied by other parts of the expression.
rw some_spec h
in this example gets "motive is not type correct", but I don't understand the motive it comes up with (I assume that's what it prints) or what's type incorrect about it:
λ (_a : Prop), (some h = 0 ∧ some_spec h = some_spec h) = (_a ∧ some_spec h = some_spec h)
Kyle Miller (Dec 07 2021 at 09:09):
@Johan Commelin My understanding is that the definition of a motive is this argument of the recursor:
example {a b c : ℕ} (h : a = b + c) : a * a + a = (b + c) * a + (b + c) :=
@eq.rec _ _ (λ (m : ℕ), a * a + a = m * a + m) rfl _ h
-- ^ motive
Kyle Miller (Dec 07 2021 at 09:13):
@Eric Rodriguez In this example, m
is like a metavariable for the expression a * a + a = m * a + m
. (Conceptually it's an expression with a metavariable, but it's also just a lambda expression.)
Kyle Miller (Dec 07 2021 at 09:19):
Here's a "motive not type correct" I've run into frequently:
example (α β : Type) [fintype α] [fintype β] (h : α = β) :
fintype.card α = fintype.card β :=
begin
rw h, -- rewrite tactic failed, motive is not type correct
end
Having it print implicit arguments, this is the motive it comes up with:
λ (x : Type),
(@fintype.card α _inst_1 = @fintype.card β _inst_2)
= (@fintype.card x _inst_1 = @fintype.card β _inst_2)
That @fintype.card x _inst_1
is the issue. The _inst_1
argument is fintype α
, not fintype x
, so there's a type error.
(Side note: it seems that rw
rewrites by taking the current goal g
(even if it's an equality) and creating motives for g = g
, putting holes in the second g
.)
Kyle Miller (Dec 07 2021 at 09:36):
simp [h]
works here, but then you have to convert rfl
example (α β : Type) [fintype α] [fintype β] (h : α = β) :
fintype.card α = fintype.card β :=
begin
simp_rw [h],
convert rfl,
end
Eric Rodriguez (Dec 07 2021 at 09:55):
But I think that's to do with the instances being wrong completely; does rw at * work? Subst should, too
Kyle Miller (Dec 07 2021 at 09:59):
Why the "but"?
Kyle Miller (Dec 07 2021 at 10:01):
I doubt rw at *
would work because I'm pretty sure it does rw
one at a time. subst
is more likely to work since it's basically revert
ing everything before creating its motive for the rewrite (at least, according to how I think it works)
Kyle Miller (Dec 07 2021 at 10:02):
rw
does work if you revert
the instances:
example (α β : Type) [fintype α] [fintype β] (h : α = β) :
fintype.card α = fintype.card β :=
begin
tactic.unfreeze_local_instances,
revert _inst_1 _inst_2,
-- ∀ [_inst_1 : fintype α] [_inst_2 : fintype β], @fintype.card α _inst_1 = @fintype.card β _inst_2
rw h,
-- ∀ [_inst_1 : fintype β] [_inst_2 : fintype β], @fintype.card β _inst_1 = @fintype.card β _inst_2
intros, congr,
end
Eric Rodriguez (Dec 07 2021 at 10:13):
rw at *
creates a goal that the instances are equal, which seems sensible to me. The reason I said but
is because it seems like a pretty transparent case, imo; if you just do a "dumb" rw
then the goal becomes @fintype.card ‹fintype α› β = @fintype.card ‹fintype β› β
, which is clear nonsense. simp_rw
is a bit cleverer and turns the lhs into @fintype.card (h.rec ‹fintype α›) β
.
Eric Rodriguez (Dec 07 2021 at 10:13):
Also, interestingly rw at *
didn't need to unfreeze instances; I worry this is a bug, as whenever I've rewritten instances without unfreezing I've gotten the weirdest behaviour possible...
Kyle Miller (Dec 07 2021 at 10:17):
Eric Rodriguez said:
if you just do a "dumb"
rw
then the goal becomes@fintype.card ‹fintype α› β = @fintype.card ‹fintype β› β
, which is clear nonsense.
Exactly, I was giving you simple example of "motive not type correct" where it's clear why the motive is not type correct.
Eric Rodriguez (Dec 07 2021 at 10:18):
also, never mind about rw at *
working, I was seeing ghosts
Last updated: Dec 20 2023 at 11:08 UTC