如何在 Ltac 中进行 "negative" 匹配?
How to do "negative" match in Ltac?
我想在某些假设存在而另一个假设不存在的情况下应用规则。我如何检查这种情况?
例如:
Variable X Y : Prop.
Axiom A: X -> Y.
Axiom B: X -> Z.
Ltac more_detail :=
match goal with
|[H1:X,<not H2:Y>|-_] =>
let H' := fresh "DET" in assert Y as H'
by (apply A;assumption)
|[H1:X,<not H2:Z>|-_] =>
let H' := fresh "DET" in assert Z as H'
by (apply B;assumption)
end.
这样,为了这个目标:
> Goal X->True. intros.
H:X
=====
True
more_detail.
会引入第二个假设 DET:
H:X
DET:Y
DET0:Z
=====
True
并且连续调用 more_detail.
会失败。
但是 more_detail.
应该始终确保 Y
和 Z
都存在,即如果只有其中一个存在,它应该 运行 另一个规则:
Goal X->Y->True. intros.
H:X
H1:Y
=====
True
> more_detail.
H:X
H1:Y
DET:Z
=====
True
并且:
> Goal X->Z->True. intros.
H:X
H0:Z
=====
True
> more_detail.
H:X
H0:Z
DET:Y
=====
True
这是一种常见的 Ltac 模式。您可以使用 fail
策略来避免在某些条件匹配时执行分支:
Variable X Y Z : Prop.
Hypothesis A : X -> Y.
Hypothesis B : X -> Z.
Ltac does_not_have Z :=
match goal with
| _ : Z |- _ => fail 1
| |- _ => idtac
end.
Ltac more_detail :=
match goal with
| H : X |- _ =>
first [ does_not_have Y;
let DET := fresh "DET" in
assert (DET := A H)
| does_not_have Z;
let DET := fresh "DET" in
assert (DET := B H) ]
end.
Goal X -> True.
intros X. more_detail. more_detail.
(* This fails *)
more_detail.
Abort.
does_not_have
策略充当否定匹配:只有当上下文中不存在其参数时它才会成功。它是这样工作的:如果 H : Z
出现在上下文中,第一个分支将匹配。简单地调用 fail
或 fail 0
会导致该分支失败,但会允许 Ltac 尝试相同 match
的其他分支。使用 fail 1
会导致当前分支 和 整个匹配失败。如果上下文中不存在 H : Z
,则第一个分支永远不会匹配,Coq 将跳过它并尝试第二个分支。由于此分支不执行任何操作,因此执行将继续执行 match
.
之后的任何策略。
在more_detail
中,first
策略可用于组合does_not_have
的多个调用;由于如果上下文包含相应的假设,first
的每个分支都会失败,因此整个构造将对您的 match
具有负面模式的影响。
我想在某些假设存在而另一个假设不存在的情况下应用规则。我如何检查这种情况?
例如:
Variable X Y : Prop.
Axiom A: X -> Y.
Axiom B: X -> Z.
Ltac more_detail :=
match goal with
|[H1:X,<not H2:Y>|-_] =>
let H' := fresh "DET" in assert Y as H'
by (apply A;assumption)
|[H1:X,<not H2:Z>|-_] =>
let H' := fresh "DET" in assert Z as H'
by (apply B;assumption)
end.
这样,为了这个目标:
> Goal X->True. intros.
H:X
=====
True
more_detail.
会引入第二个假设 DET:
H:X
DET:Y
DET0:Z
=====
True
并且连续调用 more_detail.
会失败。
但是 more_detail.
应该始终确保 Y
和 Z
都存在,即如果只有其中一个存在,它应该 运行 另一个规则:
Goal X->Y->True. intros.
H:X
H1:Y
=====
True
> more_detail.
H:X
H1:Y
DET:Z
=====
True
并且:
> Goal X->Z->True. intros.
H:X
H0:Z
=====
True
> more_detail.
H:X
H0:Z
DET:Y
=====
True
这是一种常见的 Ltac 模式。您可以使用 fail
策略来避免在某些条件匹配时执行分支:
Variable X Y Z : Prop.
Hypothesis A : X -> Y.
Hypothesis B : X -> Z.
Ltac does_not_have Z :=
match goal with
| _ : Z |- _ => fail 1
| |- _ => idtac
end.
Ltac more_detail :=
match goal with
| H : X |- _ =>
first [ does_not_have Y;
let DET := fresh "DET" in
assert (DET := A H)
| does_not_have Z;
let DET := fresh "DET" in
assert (DET := B H) ]
end.
Goal X -> True.
intros X. more_detail. more_detail.
(* This fails *)
more_detail.
Abort.
does_not_have
策略充当否定匹配:只有当上下文中不存在其参数时它才会成功。它是这样工作的:如果 H : Z
出现在上下文中,第一个分支将匹配。简单地调用 fail
或 fail 0
会导致该分支失败,但会允许 Ltac 尝试相同 match
的其他分支。使用 fail 1
会导致当前分支 和 整个匹配失败。如果上下文中不存在 H : Z
,则第一个分支永远不会匹配,Coq 将跳过它并尝试第二个分支。由于此分支不执行任何操作,因此执行将继续执行 match
.
在more_detail
中,first
策略可用于组合does_not_have
的多个调用;由于如果上下文包含相应的假设,first
的每个分支都会失败,因此整个构造将对您的 match
具有负面模式的影响。