Zulip Chat Archive
Stream: lean4
Topic: Collapse cases
Marcus Rossel (Feb 09 2022 at 09:06):
In the following (non-mwe) example, both subgoals of a cases
do pretty much the same thing. The only difference is where one of the assumptions (hi
) comes from:
cases hs.exec
case single hi =>
cases hi <;> (
have := mt (Finset.ext_iff.mp hr _).mpr <| (by assumption)
have := Finmap.ids_def'.mpr ⟨_, Eq.symm (by assumption)⟩
contradiction
)
case trans _ hi _ =>
cases hi <;> (
have := mt (Finset.ext_iff.mp hr _).mpr <| (by assumption)
have := Finmap.ids_def'.mpr ⟨_, Eq.symm (by assumption)⟩
contradiction
)
Is it possible to collapse these cases somehow, by telling the cases
tactic what hi
is supposed to be in each case (without doing the actual case distinction)?
Trebor Huang (Feb 09 2022 at 10:03):
That's called the Or pattern in some languages I suppose.
Mario Carneiro (Feb 09 2022 at 11:46):
The recently discussed on_goal
tactic would support this, using the syntax on_goal single hi, trans _ hi _ => ...
, and it would be a natural extension to use the same grammar for case
as well
Marcus Rossel (Feb 09 2022 at 11:53):
Mario Carneiro said:
The recently discussed
on_goal
tactic would support this, using the syntaxon_goal single hi, trans _ hi _ => ...
, and it would be a natural extension to use the same grammar forcase
as well
But this isn't implemented yet, right?
Mario Carneiro (Feb 09 2022 at 12:29):
no, but API design is the hard part with tactics such as this. If you want a tactic you can use right now it's pretty easy:
syntax "case' " (ident*),* " => " tacticSeq : tactic
macro_rules
| `(tactic| case' $[$xs:ident*],* => $tac) => do
let tacs ← xs.mapM fun xs => `(tactic| case $(xs[0]) $(xs[1:])* => $tac)
`(tactic| ($[$tacs]*))
example : (True → True) ∧ (True → True) := by
constructor <;> intro
case' left h, right h => apply h
Marcus Rossel (Jul 05 2022 at 19:38):
Mario Carneiro said:
If you want a tactic you can use right now it's pretty easy:
syntax "case' " (ident*),* " => " tacticSeq : tactic macro_rules | `(tactic| case' $[$xs:ident*],* => $tac) => do let tacs ← xs.mapM fun xs => `(tactic| case $(xs[0]) $(xs[1:])* => $tac) `(tactic| ($[$tacs]*))
It seems I've grown pretty dependent on this tactic over the past couple of months. And now the new TSyntax
has broken it :sweat_smile: Do there happen to be "proper" alternatives for this tactic now?
Henrik Böving (Jul 05 2022 at 19:42):
So first things first we want to use xs[0]!
here in the latest nightly, then the error becomes
type mismatch
Array.getOp! xs 0
has type
Lean.TSyntax `ident : Type
but is expected to have type
Lean.TSyntax `Lean.binderIdent : Type
Where binderIdent is defined as:
syntax binderIdent := ident <|> "_"
So I'd say a Coe (TSyntax `ident) (TSyntax `binderIdent)
is in order here right? CC @Sebastian Ullrich
Sébastien Michelland (Jul 05 2022 at 19:57):
I believe you can simply use the appropriate syntax category:
syntax "case' " (Lean.binderIdent*),* " => " tacticSeq : tactic
macro_rules
| `(tactic| case' $[$xs*],* => $tac) => do
let tacs ← xs.mapM fun xs => `(tactic| case $(xs[0]) $(xs[1:])* => $tac)
`(tactic| ($[$tacs]*))
Henrik Böving (Jul 05 2022 at 19:58):
That works as well yeah. But In general this coercion makes sense to have in the compiler I think
Mac (Jul 06 2022 at 01:37):
Henrik Böving said:
That works as well yeah. But In general this coercion makes sense to have in the compiler I think
Yeah... there are a LOT of missing TSyntax
coercions. :stuck_out_tongue_wink: I think it is mostly going to be a manually defined thing for now. Unless @Sebastian Ullrich wants PRs that fill in gaps.
Sebastian Ullrich (Jul 06 2022 at 08:22):
We should probably be conservative and add coercions only where they save a lot of $(xs[0]):ident $(xs[1:]):ident*
typing. And in this case the error even points to a probably better design as mentioned.
Last updated: Dec 20 2023 at 11:08 UTC