Coq 如何使用重写策略指定位置?
我有一个简单的列表引理,上面写着Coq 如何使用重写策略指定位置?,coq,coq-tactic,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. 现在我想用这个校对重写cons术语:,无论它们出现在校对目标中的什么地方。例如,考虑以下内容: Lemma easy_lemma : forall (n : nat) (xs ys : list nat), (n::
n::l=[n]++l
,其证明如下
Lemma cons_to_app : (forall (n: nat) (l: list nat), n :: l = [n] ++ l).
Proof.
simpl. reflexivity.
Qed.
现在我想用这个校对重写cons术语:
,无论它们出现在校对目标中的什么地方。例如,考虑以下内容:
Lemma easy_lemma : forall (n : nat) (xs ys : list nat), (n::xs) ++ (n::ys) = (n::xs) ++ ([n] ++ ys).
我想把(n::ys)
重写成[n]++ys
,证明就完成了。由于n::ys
是第二次在证明目标中出现::
,我原以为在2
处将const_重写为应用程序会起作用,但实际上它在第三次::
时起作用,并将证明目标更改为(n::xs)++n::ys=([n]++xs+[n]++ys
我可以指定什么位置使重写在
(n::ys)
术语上工作?我仍然找不到在上谈论重写的确切行为的原始源代码(除了)。链接上的帖子写于2011年,但在Coq版本8.9.1中似乎到2019年仍然有效,并且可能不会被“修复”,因为该问题以“无效”结束,称为“更改行为将破坏向后兼容性”
问题
在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次出现的n::xs
重写为[n]++xs
。第二个n::xs
恰好是第三个。:。
解决方案
简单的解决方法是给出足够的参数来告诉Coq要重写的确切内容<代码>重写(cons_to_app_ys)
在这种情况下就足够了
另一种选择是使用setoid\u rewrite
策略,它查看所有适用的子项。然而,它有时看起来过于深入的定义,确实是这个例子的情况<代码>setoid\u将cons\u重写为应用程序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
折叠应用程序
会得到[n]++(xs++n::ys)
,这与我们想要的不同,即([n]++xs)++n::ys
。我们可以观察到,setoid\u rewrite
将app
展开一次,将LHS更改为n:(xs++n::ys)
,然后实例化引理来重写最外层的:。
为了避免展开
app
,我们可以在重写之前声明不透明app.
。然后setoid\u重写。。。at 1给出了我们想要的(at 2也一样)。要恢复不透明的效果
,请使用透明
我仍然找不到在
处谈论重写的确切行为的原始源代码(除了)。链接上的帖子写于2011年,但在Coq版本8.9.1中似乎到2019年仍然有效,并且可能不会被“修复”,因为该问题以“无效”结束,称为“更改行为将破坏向后兼容性”
问题
在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次出现的n::xs
重写为[n]++xs
。第二个n::xs
恰好是第三个。:。
解决方案
简单的解决方法是给出足够的参数来告诉Coq要重写的确切内容<代码>重写(cons_to_app_ys)
在这种情况下就足够了
另一种选择是使用setoid\u rewrite
策略,它查看所有适用的子项。然而,它有时看起来过于深入的定义,确实是这个例子的情况<代码>setoid\u将cons\u重写为应用程序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
折叠应用程序
会得到[n]++(xs++n::ys)
,这与我们想要的不同,即([n]++xs)++n::ys
。我们可以观察到,setoid\u rewrite
将app
展开一次,将LHS更改为n:(xs++n::ys)
,然后实例化引理来重写最外层的:。
为了避免展开
app
,我们可以在重写之前声明不透明app.
。然后setoid\u重写。。。at 1给出了我们想要的(at 2也一样)。要恢复不透明的效果,请使用透明的我想我在某处读到,在n处重写引理使用第一次出现((n::xs)
,在这种情况下)实例化等式,然后重写它的第n次出现(第2次(n::xs)
恰好是第3次。:
)。因此,在n
没有将cons\u重写为将重写(n::ys)
的应用程序。你至少需要重写(cons\u to\u app\uys)
。哦,这很有趣。我正在看战术文档,rewrite at
的条目指的是pattern at
,它说“β-展开只考虑项的出现次数num+。出现次数从左到右。”你记得你在哪里读到你说的吗@马克·布布勒的解释是正确的,但我也不记得我在哪里见过它。@马克这是我发现的最好的:。我想我在某处读到,在n处重写引理
使用第一次出现((n::xs)
,在这种情况下)实例化等式,然后重写它的第n次出现((n::xs)的第2次)
正好是第三个。:。
)。因此,在n
没有将cons\u重写为将重写(n::ys)
的应用程序。你至少需要重写(cons\u to\u app\uys)
。哦,这很有趣。我正在查看战术文档和
rewrite的条目