Recursion 如何在Coq中只展开一次递归函数

Recursion 如何在Coq中只展开一次递归函数,recursion,coq,unfold,Recursion,Coq,Unfold,下面是一个递归函数all_zero,用于检查自然数列表中的所有成员是否为零: Require Import Lists.List. Require Import Basics. Fixpoint all_zero ( l : list nat ) : bool := match l with | nil => true | n :: l' => andb ( beq_nat n 0 ) ( all_zero l' ) end. 现在,假设我有以下目标 true =

下面是一个递归函数
all_zero
,用于检查自然数列表中的所有成员是否为零:

Require Import Lists.List.
Require Import Basics.

Fixpoint all_zero ( l : list nat ) : bool :=
  match l with
  | nil => true
  | n :: l' => andb ( beq_nat n 0 ) ( all_zero l' )
  end.
现在,假设我有以下目标

true = all_zero (n :: l')
我想用
展开
策略将其转换为

true = andb ( beq_nat n 0 ) ( all_zero l' )
不幸的是,我不能用一个简单的
展开所有零
,因为该策略将急切地查找并替换所有
所有零
的实例,包括一个以一次展开的形式出现的实例,它会变得一团糟。有没有办法避免这种情况,只展开一次递归函数

我知道我可以通过证明与X的
assert(…)的特殊等价性来获得相同的结果,但这是低效的。我想知道是否有类似于
展开

尝试的简单方法

unfold all_zero; fold all_zero.
至少对我来说,这会产生:

true = (beq_nat n 0 && all_zero l)%bool

在我看来,
siml
会做你想做的事。如果您有一个更复杂的目标,要应用的函数和要保留的函数,您可能需要使用
cbv
策略的各种选项(请参阅)。

unfold
后跟
fold
确实适用于
all\u zero
,但不适用于多态递归函数。这里有一个例子:
Fixpoint none{X:Type}(t:X->bool)(l:list X):bool:=将l与| nil=>true | h::l'=>和b(negb(th))(none t l')结束。
展开无
后接
折叠无
会导致以下错误消息:
错误:无法推断无的隐式参数X。
因此,我认为一次展开递归函数的通用解决方案首先必须避免使用
展开
,除非有某种方法可以将参数信息提供给
fold
。您可以通过写入
@none
使
none
的隐式参数
X
显式。如果您编写
fold@none.
,那么Coq能够明确给出参数,并在当前上下文中搜索合适的
X
,就像它对其他所有量化变量
t
l
所做的一样。如果存在歧义,您还可以明确指定相应的变量,即
fold(@none X)
。您还可以证明
所有nl、all_zero(n::l)=和b(beq_nat n 0)(all_zero l)
,并用它重写。