Zulip Chat Archive
Stream: metaprogramming / tactics
Topic: tactic.induction does not keep case names
Henning Dieterichs (Jan 05 2021 at 15:52):
I'm very new to tactic programming. I want to apply induction, however, when I use tactic.induction
inside my tactic, it loses the goal names:
import tactic
import data.finset
inductive Tree (α: Type)
| leaf (a: α): Tree
| branch (tr1 tr2: Tree) : Tree
variables { α: Type } [decidable_eq α]
def Tree.leaves_list: Tree α → list α
| (Tree.leaf a) := { a }
| (Tree.branch tr1 tr2) := tr1.leaves_list ++ tr2.leaves_list
def Tree.leaves (a: Tree α): finset α := a.leaves_list.to_finset
def Tree.disjoint : Tree α → Prop
| (Tree.leaf leaf) := true
| (Tree.branch tr1 tr2) := tr1.disjoint ∧ tr2.disjoint ∧ disjoint tr1.leaves tr2.leaves
open tactic expr
namespace tactic
namespace interactive
setup_tactic_parser
meta def disjoint_induction (n: parse parser.pexpr) : tactic unit :=
do
e ← to_expr n,
tactic.induction e,
skip
end interactive
end tactic
lemma Tree.leaves_list.nodup { t: Tree α } (tree_disjoint: t.disjoint):
t.leaves_list.nodup :=
begin
disjoint_induction t,
end
This is the goal:
2 goals
α : Type,
_inst_1 : decidable_eq α,
t : α,
tree_disjoint : (Tree.leaf t).disjoint
⊢ (Tree.leaf t).leaves_list.nodup
α : Type,
_inst_1 : decidable_eq α,
t_tr1 t_tr2 : Tree α,
t_ih_tr1 : t_tr1.disjoint → t_tr1.leaves_list.nodup,
t_ih_tr2 : t_tr2.disjoint → t_tr2.leaves_list.nodup,
tree_disjoint : (t_tr1.branch t_tr2).disjoint
⊢ (t_tr1.branch t_tr2).leaves_list.nodup
This is what I would like to get:
2 goals
case Tree.leaf
α : Type,
_inst_1 : decidable_eq α,
t : α,
tree_disjoint : (Tree.leaf t).disjoint
⊢ (Tree.leaf t).leaves_list.nodup
case Tree.branch
α : Type,
_inst_1 : decidable_eq α,
t_tr1 t_tr2 : Tree α,
t_ih_tr1 : t_tr1.disjoint → t_tr1.leaves_list.nodup,
t_ih_tr2 : t_tr2.disjoint → t_tr2.leaves_list.nodup,
tree_disjoint : (t_tr1.branch t_tr2).disjoint
⊢ (t_tr1.branch t_tr2).leaves_list.nodup
What do I do wrong?
Jannis Limperg (Jan 05 2021 at 15:59):
The goal names are called 'case tags' and they are set by tactic.interactive.induction
, which wraps tactic.induction
. Look at the private function set_cases_tags
in init/meta/tactic/interactive.lean
(above the definition of tactic.interactive.induction
).
Henning Dieterichs (Jan 05 2021 at 19:15):
Thanks, that hint helped me! I'm just calling interactive.induction
now. Now I want to preprocess some cases. However, if I do this with '[all_goals { ... }]
I lose all the tags again...
meta def ant_disjoint_induction (hp : parse cases_arg_p) (h : parse (tk "have" *> ident)) (rec_name : parse using_ident) (ids : parse with_ident_list)
(revert : parse $ (tk "generalizing" *> ident*)?) : tactic unit :=
do
induction hp rec_name ids revert,
`[
all_goals {
unfold Tree.disjoint at tree_disjoint,
}
],
skip,
Simon Hudon (Jan 05 2021 at 19:21):
all_goals
is not what is dismissing the tags, unfold
is. You can wrap it in propagate_tags
Henning Dieterichs (Jan 05 2021 at 19:25):
~ohh awesome! But how can I wrap it within '[ ... ]?
~
This does it:
do
induction hp rec_name ids revert,
propagate_tags `[
all_goals {
unfold Tree.disjoint at tree_disjoint,
}
],
skip
thank you!
Simon Hudon (Jan 05 2021 at 19:33):
Why do you need `[ ... ]
?
Henning Dieterichs (Jan 05 2021 at 19:35):
I don't know much about tactics programming yet. ` [ ...]
seemed to be the easiest way to transform a repetitive pattern into a reusable tactic.
Henning Dieterichs (Jan 05 2021 at 19:35):
But
all_goals $ propagate_tags `[
unfold Tree.disjoint at tree_disjoint
],
finally does it.
Last updated: Dec 20 2023 at 11:08 UTC