我想简单地编写gcd
的这个递归变体,"自然而然地#34;尽可能在Coq。
Require Import Arith.
Require Import Program.
Program Fixpoint gcd (a b:nat) {measure b} :=
if 0 <? b then gcd b (a mod b) else a.
Next Obligation.
(* Here I need to prove that `a mod b < b` *)
apply Nat.mod_upper_bound.
现在我需要证明b <> 0
但我丢失了0 <? b = false
分支中的信息。
a, b : nat
gcd : nat -> forall b0 : nat, b0 < b -> nat
============================
b <> 0
如何保留if语句中的信息?
我知道我可以使用match
,但是如何用if
来编写?)
Program Fixpoint gcd (a b:nat) {measure b} :=
match b with 0 => a | S b' => gcd b (a mod b) end.
Next Obligation.
apply Nat.mod_upper_bound.
(* Goal: S b' <> 0 *)
congruence.
Defined.
===编辑===
我注意到Coq(在更新版本中?)会记住0 <? b
与匹配模式(本例中为true
或false
)之间的关联。或者它是Program
的一个特征?无论如何,我认为if
基本上已经扩展到这个match
声明,但显然它不是......
Program Fixpoint gcd (a b:nat) {measure b} : nat:=
match 0<?b with
| true => gcd b (a mod b)
| false => a
end.
Next Obligation.
apply Nat.mod_upper_bound.
(* now we have ` true = (0 <? b)` in the assumptions, and the goal `b <> 0` *)
now destruct b.
Defined.
答案 0 :(得分:2)
可以使用lt_dec
来做到这一点。
lt_dec
: forall n m : nat, {n < m} + {~ n < m}
这样我们就可以在上下文中保留我们需要的证明,这与使用<?
时不同,后者返回bool
。
Require Import Arith.
Require Import Program.
Program Fixpoint gcd (a b:nat) {measure b} :=
if lt_dec 0 b then gcd b (a mod b) else a.
Next Obligation.
apply Nat.mod_upper_bound.
now destruct H.
Defined.
是的,它是Program
的一项功能。实际上,参考手册以非常清晰的方式解释了它(见§24.1):
产生平等。
match
表达式总是由相应的相等性推广。例如,表达式:match x with | 0 => t | S n => u end.
将首先改写为:
(match x as y return (x = y -> _) with | 0 => fun H : x = 0 -> t | S n => fun H : x = S n -> u end) (eq_refl n).
以下是if
不同的原因:
为了更好地控制均等的生成,如果指定了
return
或in
子句,则类型检查器将直接回退到Coq通常的依赖模式匹配类型。同样,if
构造不会被Program
专门处理,因此代码中的布尔测试不会自动反映在义务中。可以使用dec
组合器来获得正确的假设,如:Coq < Program Definition id (n : nat) : { x : nat | x = n } := if dec (leb n 0) then 0 else S (pred n).