如何使用重写策略指定位置?

时间:2019-06-21 04:38:06

标签: coq coq-tactic

我有一个简单的引理清单,上面写着n::l = [n]++l,其证据显示在下面。

Lemma cons_to_app : (forall (n: nat) (l: list nat),  n :: l = [n] ++ l).
Proof.
  simpl. reflexivity.
Qed.

现在,我想在证明目标中出现的任何地方都使用此证明重写约束条件::。例如,考虑以下。

Lemma easy_lemma : forall (n : nat) (xs ys : list nat), (n::xs) ++ (n::ys) = (n::xs) ++ ([n] ++ ys).

我想将(n::ys)改写为[n] ++ ys并完成证明。由于n::ys::第二次出现在证明目标中,因此我认为rewrite const_to_app at 2可以工作,但实际上它作用于第三个::并改变了证明目标到(n :: xs) ++ n :: ys = ([n] ++ xs) ++ [n] ++ ys

我可以指定哪个位置以使(n::ys)期限的重写工作?

1 个答案:

答案 0 :(得分:2)

我仍然找不到谈论rewrite at(除the one eponier mentioned之外)确切行为的原始资料。链接上的帖子写于2011年,但对于Coq版本8.9.1而言,它似乎在2019年仍然有效,并且可能不会被“修复”,因为该问题已被关闭为“无效”,并说“改变行为会中断”。向后兼容”。


问题

rewrite lemma at n使用第一个匹配项实例化等式,然后重写其第n个匹配项。

给出引理证明

Lemma easy_lemma :
  forall (n : nat) (xs ys : list nat), (n::xs) ++ (n::ys) = (n::xs) ++ ([n] ++ ys).

以及用于重写的引理

Lemma cons_to_app : (forall (n: nat) (l: list nat),  n :: l = [n] ++ l).

rewrite cons_to_app at n.总是选择子项n :: xs,然后将第n :: xs的第n个实例重写为[n] ++ xs。第二个n :: xs恰好是第三个_ :: _

解决方案

简单的解决方案是提供足够的参数来告诉Coq要重写的确切内容。在这种情况下,rewrite (cons_to_app _ ys)就足够了。

一种替代方法是使用setoid_rewrite策略,该策略查看所有适用的子术语。但是,有时候对定义的理解太深了,这个例子的确如此。 setoid_rewrite cons_to_app at 1.给予

1 subgoal
n : nat
xs, ys : list nat
______________________________________(1/1)
[n] ++
(fix app (l m : list nat) {struct l} : list nat := match l with
                                                   | [] => m
                                                   | a :: l1 => a :: app l1 m
                                                   end) xs (n :: ys) = (n :: xs) ++ [n] ++ ys

折叠app会得到[n] ++ (xs ++ n :: ys),这与我们想要的([n] ++ xs) ++ n :: ys不同。我们可以观察到setoid_rewrite展开了app一次,将LHS更改为n :: (xs ++ n :: ys),然后实例化引理来重写最外面的_ :: _

为避免展开app,我们可以在重写之前声明Opaque app.。然后setoid_rewrite ... at 1给出了我们想要的(at 2也给出了)。要恢复Opaque的效果,请使用Transparent