假设我在Coq中编写了一个Fixpoint算法,它总结了所有"一半"一个数字:
Fixpoint sum_of_halves (a : nat) : nat :=
match a with
| 0 => 0
| 2 * k => a + (sum_of_halves k)
| S (2 * k) => a + (sum_of_halves k)
end.
尝试评估算法会得到:Error: Invalid notation for pattern.
如何让Coq识别a是偶数还是奇数,并将其与2 * k
或S (2 * k)
匹配?
答案 0 :(得分:2)
Coq只能在构造函数上match
。 nat
有两个构造函数O
和S
,因此您无法在2 * k
上匹配。您必须使用非match
构造或非nat
类型或不同的算法。
答案 1 :(得分:0)
您需要证明给定自然数a
只有三种情况。 a
为0,a
为另一个数字k
和k < a
的两倍,或a
为双k
+ 1且k < a
,这三种情况都是排他性的(这很重要,否则使模式匹配成为可能会导致不一致)。
幸运的是,所有这一切都可以完成。这是一个有点高级的Coq编程,但它已经在ZArith
中以某种方式完成了。这是一个解决方案。
首先请注意,另一个数字已由Coq库div2
中的一个函数提供。
Require Import Arith Nat.
Definition cases_div2 (a : nat) :
{k : nat | a = 2 * k /\ k < a}+{k : nat | a = S (2 * k) /\ k < a}+{a=0}.
destruct a as [ | a'].
right; reflexivity.
case_eq (odd (S a')); intros odd_a.
left; right; exists (div2 (S a')); rewrite (div2_odd (S a')) at 1.
split.
rewrite odd_a; simpl b2n; ring.
apply lt_div2; auto with arith.
left; left; exists (div2 (S a')); rewrite (div2_odd (S a')) at 1.
split.
rewrite odd_a; simpl b2n; ring.
apply lt_div2; auto with arith.
Defined.
现在,您可以使用cases_div2
对您的数字a进行模式匹配,但仍然不足以定义您的函数,因为使用Fixpoint
的递归依赖于在前任上发生的递归调用,而这里k
不能写为适用于任何输入a
的前趋模式。你需要一种更强大的递归。我通常依靠Function
或Fix
来进行这种强大的递归。以下是Fix
Definition sum_of_halves : nat -> nat :=
Fix Arith.Wf_nat.lt_wf (fun _ => nat)
(fun a (sum_of_halves' : forall y, y < a -> nat) =>
match cases_div2 a with
| inright h => 0
| inleft (inl (exist _ k (conj keq klt))) =>
a + sum_of_halves' k klt
| inleft (inr (exist _ k (conj keq klt))) =>
a + sum_of_halves' k klt
end).
然后推理sum_of_halves
你需要通过有根据的归纳推理并使用Fix_eq
。
这是一种可能性。