如何在Coq简化过程中应用一次函数?

如何在Coq简化过程中应用一次函数?,coq,coq-tactic,Coq,Coq Tactic,据我所知,Coq中的函数调用是不透明的。 有时,我需要使用展开来应用它,然后使用折叠将函数定义/主体转换回其名称。这通常是乏味的。我的问题是,有没有更简单的方法让应用函数调用的特定实例 举个简单的例子,对于列表l,为了证明正确的追加[]不会改变l: Theorem nil_right_app: forall {Y} (l: list Y), l ++ [] = l. Proof. induction l. reflexivity. 这就剩下: 1 subgoals Y : Ty

据我所知,Coq中的函数调用是不透明的。 有时,我需要使用
展开
来应用它,然后使用
折叠
将函数定义/主体转换回其名称。这通常是乏味的。我的问题是,有没有更简单的方法让应用函数调用的特定实例

举个简单的例子,对于列表
l
,为了证明正确的追加
[]
不会改变
l

Theorem nil_right_app: forall {Y} (l: list Y), l ++ [] = l.
Proof.
  induction l. 
    reflexivity. 
这就剩下:

1 subgoals
Y : Type
x : Y
l : list Y
IHl : l ++ [] = l
______________________________________(1/1)
(x :: l) ++ [] = x :: l
现在,我需要应用一次
++
(即
app
)的定义(假装目标中还有其他
++
,我不想应用/扩展)。目前,我知道实现此一次性应用程序的唯一方法是首先展开
++
,然后将其折叠:

    unfold app at 1. fold (app l []).
给予:

______________________________________(1/1)
x :: l ++ [] = x :: l
但是这很不方便,因为我必须弄清楚在
fold
中使用的术语的形式。我做的是计算,不是Coq。我的问题归结为:


是否有一种更简单的方法来实现此一次性函数应用程序以达到相同的效果?

如果您想让Coq为您执行一些计算,您可以使用
siml
compute
vm\u compute
。如果函数的定义是不透明的,上述解决方案将失败,但您可以首先证明一个重写引理,例如:

forall (A:Type) (a:A) (l1 l2: list A), (a :: l1) ++ l2 = a :: (l1 ++ l2).
使用您的技术,然后在必要时用它重写

下面是一个使用
siml
的示例:

Theorem nil_right_app: forall {Y} (l: list Y), l ++ nil = l.
Proof.
(* solve the first case directly *)
intros Y; induction l as [ | hd tl hi]; [reflexivity | ]. 
simpl app. (* or simply "simpl." *)
rewrite hi.
reflexivity.
Qed.

为了回答您的评论,我不知道如何告诉
cbv
compute
只计算某个符号。请注意,在您的情况下,他们似乎过于急切地进行计算,
simple
工作得更好。

所有Coq的定义都不是不透明的,但有一些方法可以防止Coq自动展开定义(例如,在使用策略定义函数时使用
Qed
。而不是
定义的
)。你所说的不透明是什么意思?谢谢。你的意思是我可以像“compute app at 1”那样使用“compute”还是类似的东西?你能举个例子吗。我查看了compute和cbv的coq文档,但找不到一个具体的例子。用一个例子和几句话更新