我如何实施迭代假设的 coq 策略?
How can I implement a coq tactic that iterates over the hypotheses?
作为我的一般问题的最小示例,假设我们有以下内容:
Parameter C: Prop.
Definition blah := C.
我想实施一种在目标的所有假设中自动展开 blah
的策略。
我试过这个:
Ltac my_auto_unfold := repeat match goal with
| [ H: ?P |- ?P ] => unfold blah in H
end.
Theorem g: blah -> blah -> blah.
Proof.
intros.
my_auto_unfold.
但只有一个假设blah
展开。
您的代码段的问题在于 [ H: ?P |- ?P ]
在这种情况下将始终匹配。第一次匹配 H : blah
,第二次匹配 H : C
—— 因为 C 和 blah 在 Coq 中是可转换的 —— 展开不会改变任何东西,因此中止 repeat
.
我会写
Ltac my_auto_unfold nam := repeat lazymatch goal with
| [ H : nam |- _ ] => unfold nam in H
end.
Theorem g: blah -> blah -> blah.
Proof.
intros.
my_auto_unfold blah. auto. Qed.
你甚至可以写
Theorem g: blah -> blah -> blah.
Proof.
intros.
match goal with
| [ |- ?p] => my_auto_unfold p
end.
auto. Qed.
如果你愿意的话。
我认为您可能正在寻找 progress
战术。如果你这样做:
Ltac my_auto_unfold := repeat match goal with
| [ H: ?P |- ?P ] => progress unfold blah in H
end.
那么它将在两个假设中展开blah
。你甚至可以这样做:
Ltac in_all_hyps tac :=
repeat match goal with
| [ H : _ |- _ ] => progress tac H
end.
概括这种模式。请注意,这可能 运行 每个假设中的策略多次。
如果你想运行一次遍历所有假设,按顺序,这要困难得多(特别是如果你想保留 evar 上下文而不向证明项添加愚蠢的东西)。这是实现此目的的快捷方式(假设您的策略不会影响目标):
Parameter C: Prop.
Definition blah := C.
Definition BLOCK := True.
Ltac repeat_until_block tac :=
lazymatch goal with
| [ |- BLOCK -> _ ] => intros _
| [ |- _ ] => tac (); repeat_until_block tac
end.
Ltac on_each_hyp_once tac :=
generalize (I : BLOCK);
repeat match goal with
| [ H : _ |- _ ] => revert H
end;
repeat_until_block
ltac:(fun _
=> intro;
lazymatch goal with
| [ H : _ |- _ ] => tac H
end).
Theorem g: blah -> blah -> fst (id blah, True).
Proof.
intros.
on_each_hyp_once ltac:(fun H => unfold blah in H).
这个想法是你插入一个虚拟标识符来标记你在目标中的位置(即标记可以引入多少变量),然后你将所有上下文恢复到目标中,这样你可以一次重新引入一个假设的上下文,运行对您刚刚引入的每个假设采用策略。
作为我的一般问题的最小示例,假设我们有以下内容:
Parameter C: Prop.
Definition blah := C.
我想实施一种在目标的所有假设中自动展开 blah
的策略。
我试过这个:
Ltac my_auto_unfold := repeat match goal with
| [ H: ?P |- ?P ] => unfold blah in H
end.
Theorem g: blah -> blah -> blah.
Proof.
intros.
my_auto_unfold.
但只有一个假设blah
展开。
您的代码段的问题在于 [ H: ?P |- ?P ]
在这种情况下将始终匹配。第一次匹配 H : blah
,第二次匹配 H : C
—— 因为 C 和 blah 在 Coq 中是可转换的 —— 展开不会改变任何东西,因此中止 repeat
.
我会写
Ltac my_auto_unfold nam := repeat lazymatch goal with
| [ H : nam |- _ ] => unfold nam in H
end.
Theorem g: blah -> blah -> blah.
Proof.
intros.
my_auto_unfold blah. auto. Qed.
你甚至可以写
Theorem g: blah -> blah -> blah.
Proof.
intros.
match goal with
| [ |- ?p] => my_auto_unfold p
end.
auto. Qed.
如果你愿意的话。
我认为您可能正在寻找 progress
战术。如果你这样做:
Ltac my_auto_unfold := repeat match goal with
| [ H: ?P |- ?P ] => progress unfold blah in H
end.
那么它将在两个假设中展开blah
。你甚至可以这样做:
Ltac in_all_hyps tac :=
repeat match goal with
| [ H : _ |- _ ] => progress tac H
end.
概括这种模式。请注意,这可能 运行 每个假设中的策略多次。
如果你想运行一次遍历所有假设,按顺序,这要困难得多(特别是如果你想保留 evar 上下文而不向证明项添加愚蠢的东西)。这是实现此目的的快捷方式(假设您的策略不会影响目标):
Parameter C: Prop.
Definition blah := C.
Definition BLOCK := True.
Ltac repeat_until_block tac :=
lazymatch goal with
| [ |- BLOCK -> _ ] => intros _
| [ |- _ ] => tac (); repeat_until_block tac
end.
Ltac on_each_hyp_once tac :=
generalize (I : BLOCK);
repeat match goal with
| [ H : _ |- _ ] => revert H
end;
repeat_until_block
ltac:(fun _
=> intro;
lazymatch goal with
| [ H : _ |- _ ] => tac H
end).
Theorem g: blah -> blah -> fst (id blah, True).
Proof.
intros.
on_each_hyp_once ltac:(fun H => unfold blah in H).
这个想法是你插入一个虚拟标识符来标记你在目标中的位置(即标记可以引入多少变量),然后你将所有上下文恢复到目标中,这样你可以一次重新引入一个假设的上下文,运行对您刚刚引入的每个假设采用策略。