我正在尝试在Coq中使用以下函数来实现使用n个元素构建Braun树的函数,但是Coq给了我一个错误,它无法猜测fix参数的减小:
SELECT phone
FROM members
WHERE phone REGEXP '^[[:alpha:]]+$'
我知道不是问题出现在偶数和奇数情况下,因为当我删除偶数/奇数情况时,它给出了相同的错误:
Fixpoint copy (x : V) (n : nat) : BraunTree :=
let
fix copy2 (a : V) (i : nat) : (BraunTree * BraunTree) :=
match i with
| 0 => (T a E E,E)
| _ => match Nat.odd i with
| true => let m := ((i - 1) / 2) in
let (s,t) := copy2 a m in
((T a s t),(T a t t))
| false => let m := ((i - 2) / 2) in
let (s,t) := copy2 a m in
((T a s s),(T a s t))
end
end
in
match copy2 x n with
|(_,snd) => snd
end.
我怎样才能说服Coq我实际上是在减少争论?
BraunTree的编辑类型:
Fixpoint copy (x : V) (n : nat) : BraunTree :=
let
fix copy2 (a : V) (i : nat) : (BraunTree * BraunTree) :=
match i with
| 0 => (T a E E,E)
| _ => let m := ((i - 1) / 2) in
let (s,t) := copy2 a m in
((T a s t),(T a t t))
end
in
match copy2 x n with
|(_,snd) => snd
end.
答案 0 :(得分:4)
Fixpoint
/ fix
仅允许对语法上较小的参数进行递归调用。
Fixpoint example (n : nat) :=
... (* There must be a match on [n] somewhere *)
... match n with
| O => base_case (* no recursive call allowed *)
| S m =>
... (example m)
(* We can only call [example] on [m], or some even smaller value obtained by matching on [m] *)
end ...
尤其是,不允许对通过某些任意函数(在这种情况下,div
中的sub
和copy2 a ((i-1) / 2)
获得的值进行递归调用。
这是三个选项:
选择自然数的另一种表示形式,以便其上的模式匹配自然分解为所需定义的不同分支(基本情况(零),偶数,奇数)。
利用递归深度实际上受n
限制的事实,因此我们可以将n
用作“燃料”,我们知道在完成之前实际上并不会耗尽它。 / p>
巧妙地提取出递减参数的子项以进行递归调用。与以前的解决方案相比,此解决方案的通用性和鲁棒性较低。与终止检查器的对抗要困难得多。
我们有三种情况:零,偶数和奇数。幸运的是,标准库的类型具有几乎相同的结构,positive
:
Inductive positive := (* p > 0 *)
| xH (* 1 *)
| xI (p : positive) (* 2p + 1 *)
| xO (p : positive) (* 2p *)
.
将类型positive
指向一个额外的零,我们得到N
:
Inductive N :=
| N0 (* 0 *)
| Npos (p : positive) (* p > 0 *)
.
还有一个转换函数N.of_nat : nat -> N
,尽管如果转换变得很烦人,最好在各处使用N
而不是nat
,
最终定义是从对N
的案例分析开始的,揭示positive
数字的案例是用fix
点处理的,基本案例是1而不是0。我们必须转移一些细节,因为偶数情况是2p而不是2p + 2,因此我们必须做(i-1,i)而不是一对大小为(i + 1,i)的树。但是总的来说,递归案例仍然很自然地符合非正式规范:
Require Import NArith PArith.
Parameter V : Type.
Inductive BraunTree : Type :=
| E : BraunTree
| T: V -> BraunTree -> BraunTree -> BraunTree.
Definition copy (x : V) (n : N) : BraunTree :=
match n with
| N0 => E
| Npos p =>
let
(* copy2 a i : a tree of (i-1) copies of a, and another of i copies of a *)
fix copy2 (a : V) (i : positive) : (BraunTree * BraunTree) :=
match i with
| xH => (* i = 1 *)
(E, T a E E)
| xI p => (* i = 2p + 1 *)
let (s,t) := copy2 a p in
((T a t s),(T a t t))
| xO p => (* i = 2p *)
let (s,t) := copy2 a p in
((T a s s),(T a t s))
end
in
match copy2 x p with
|(_,snd) => snd
end
end.
我们向fix
添加燃料作为递减参数。如果n = i = 0
,我们就用光了,所以我们知道结果应该是什么。
(* note: This doesn't need to be a Fixpoint *)
Definition copy (x : V) (n : nat) : BraunTree :=
let
fix copy2 (a : V) (n : nat) (i : nat) : (BraunTree * BraunTree) :=
match n with
| O => (T a E E,E)
| S n' =>
match i with
| O => (T a E E,E)
| _ =>
if Nat.odd i then
let m := div2 ((i - 1) / 2) in
let (s,t) := copy2 a n' m in
((T a s t),(T a t t))
else
let m := div2 ((i - 2) / 2) in
let (s,t) := copy2 a n' m in
((T a s s),(T a s t))
end
end
in
match copy2 x n n with
|(_,snd) => snd
end.
在以下情况下效果很好:
如果这两个假设中的任何一个都不成立,则需要用option
填充代码。
如前所述,Coq对于减少参数有严格的规定。通常的解释是,我们只能递归调用通过递减参数(或传递式,其子项之一)通过模式匹配获得的子项。
一个明显的限制是,因为条件是句法上的(即Coq查看定义以跟踪递减参数的出处),所以参数n
最多只能减少一个常数(与相对于n
),因为在定义中只有match
个有限。特别是,无法对除以2的结果进行递归调用,因为这表示减少n/2
,即n
中线性的值。
不管好坏,Coq的终止标准实际上比这聪明一点:可以将递减的参数传递给嵌套的固定点,然后通过它跟踪“子项”关系。
实际上,Peano nat
的除法可以这样定义:Coq可以判断结果是股息的子项:
Definition div2 (n : nat) :=
let fix d2 (n1 : nat) (n2 : nat) {struct n1} :=
match n2 with
| S (S n2') =>
match n1 with
| O => n1
| S n1' => d2 n1' n2'
end
| _ => n1
end
in d2 n n.
这个想法是写一个fix
的两个参数点(有点像燃料解决方案),它们的起点是相等的(d2 n n
),我们删除了两个我们从另一个(S
中删除的每个一个 n2
中的一个S
中的n1
个构造函数。重要详细信息:
在所有非递归情况下,我们返回n1
(无论如何返回 not 0
),然后保证它是以下条件的子项最顶部的n
。
并且该函数必须在n1
(我们返回的术语)中递减,而不是在n2
(Coq仅跟踪递减参数的子项)中递减。
确保div2 n
是n
的子项(不是 strict子项(或 proper子项))的所有原因,因为{{1 }}可以是n
。
这与以前的基于燃料的解决方案有相似之处,但是在这里,递减的论点比欺骗类型检查器的设备更为重要。
这项技术是无缺点编程的一种变体。 (请注意,尽管约束条件与文献中讨论的约束条件并不完全相同,例如,当重点是避免内存分配而不是通过结构井来确保终止时,基础。)
O
的定义一旦有了copy
,我们就可以通过一些调整来定义div2
,以获得copy
和i-1
作为{{的正确子项 1}},再次通过模式匹配。下面,i-2
和i
是i'
的适当子项(通过目视检查),i''
和i
是div2 i'
和{ {1}}(根据div2 i''
的定义)。通过传递性,它们是i'
的适当子项,因此终止检查器接受。
i''