Zulip Chat Archive
Stream: mathlib4
Topic: A twist on `obtain`
Heather Macbeth (Apr 15 2023 at 19:14):
I'm looking for metaprogramming help on a macro which is intended to slightly extend the capabilities of obtain
, letting it deal with equalities in products like (x, 3) = (1, 3)
as if they were "and"-statements like x = 1 ∧ 3 = 3
. Here's what I have currently:
import Mathlib.Data.Prod.Basic
macro_rules
| `(tactic| obtain $pat? $[ : $ty]? := $val) =>
`(tactic| rw [Prod.mk.inj_iff] at * ; obtain $pat? $[ : $ty]? := $val)
It works on a simple example like
example (h : (x, 3) = (1, 3)) : False := by
obtain ⟨h1, h2⟩ := h
producing the goal state
x : ℕ
h1 : x = 1
h2 : 3 = 3
⊢ False
Heather Macbeth (Apr 15 2023 at 19:16):
But the rw ... at *
is obviously too heavy-handed. Here's an example of why:
example (h : (x, 3) = (1, 3) ∨ y = 2) (h' : (3, 4) = (z, w)): False := by
obtain h1 | h2 := h
The current version of the macro produces the goal state
x y z w : ℕ
h' : 3 = z ∧ 4 = w
h1 : x = 1 ∧ 3 = 3
⊢ False
x y z w : ℕ
h' : 3 = z ∧ 4 = w
h2 : y = 2
⊢ False
whereas I'd like it to produce the goal state
x y z w : ℕ
h' : (3, 4) = (z, w)
h1 : (x, 3) = (1, 3)
⊢ False
x y z w : ℕ
h' : (3, 4) = (z, w)
h2 : y = 2
⊢ False
Heather Macbeth (Apr 15 2023 at 19:19):
Could I get some help adjusting my macro? Effectively I want it to perform
replace h := Iff.mp Prod.mk.inj_iff h
obtain ⟨h1, h2⟩ := h
if the $val
in the macro is a named hypothesis h
, and
have h := Iff.mp Prod.mk.inj_iff $val
obtain ⟨h1, h2⟩ := h
if the $val
in the macro is some compound term.
Kyle Miller (Apr 15 2023 at 19:37):
Right now for simple-enough hypotheses (where the induced equalities are either between variables or between things that are defeq), it "works"
example (h : (x, 3) = (1, 3)) (h' : x = y) : False := by
obtain ⟨h1, h2⟩ := h
/- y: ℕ
h': 1 = y
⊢ False -/
though that obtain
is equivalent to doing obtain ⟨⟩ := h
, since these rcases patterns ignore any unused variables. Here we're asking obtain
to do cases on h
.
Kyle Miller (Apr 15 2023 at 19:38):
I wonder if it would be possible to extend rcases patterns to have another type of pattern specifically for equalities. Like maybe you could do obtain rfl h1 h2 := h
, where rfl
takes some number of arguments to name hypotheses for each component in the constructor injectivity lemma.
Kyle Miller (Apr 15 2023 at 19:41):
For your other example, it might look like
example (h : (x, 3) = (1, 3) ∨ y = 2) (h' : (3, 4) = (z, w)): False := by
obtain rfl h1 _ | h2 := h
/- Goal 1
x y z w: ℕ
h': (3, 4) = (z, w)
h1: x = 1
⊢ False
Goal 2
x y z w: ℕ
h': (3, 4) = (z, w)
h2: y = 2
⊢ False -/
(underscore in that rfl
since we don't care about 3 = 3
)
Heather Macbeth (Apr 15 2023 at 19:46):
I'm actually less interested in a principled approach with flexible syntax than in a hack that would work in this precise example, allowing me to pretend that (x, 3) = (1, 3)
means x = 1 \and 3 = 3
by definition -- this is for teaching :)
Kyle Miller (Apr 15 2023 at 19:48):
I get that -- I just don't have any good ideas myself for getting a hack to work that won't have unexpected consequences
Kyle Miller (Apr 15 2023 at 19:49):
but maybe to answer your immediate question, `(tactic| obtain $pat? $[ : $ty]? := $val:ident)
should let you match on the case you were asking about
Kyle Miller (Apr 15 2023 at 19:56):
@Heather Macbeth I haven't tested it (and I didn't adapt it to your Iff.mp ...
formulation), but maybe this will help?
macro_rules
| `(tactic| obtain $pat? $[ : $ty]? := $val) =>
if Syntax.isIdent val then
let h := val.raw.getId
`(tactic| rw [Prod.mk.inj_iff] at $(mkIdent h):ident ; obtain $pat? $[ : $ty]? := $val)
else
`(tactic| have h := $val; rw [Prod.mk.inj_iff] at h ; obtain $pat? $[ : $ty]? := h)
Kyle Miller (Apr 15 2023 at 19:56):
(There's probably a more elegant way to handle checking whether val
is an identifier and getting its name, or better, an Ident
.)
Last updated: Dec 20 2023 at 11:08 UTC