Recursion 依赖参数的结构递归

Recursion 依赖参数的结构递归,recursion,coq,dependent-type,convoy-pattern,Recursion,Coq,Dependent Type,Convoy Pattern,我正试着用Coq写埃拉托什尼的筛子。我有一个函数crossout:forall{n:nat},vectorbooln->nat->vectorbooln。当筛子找到一个素数时,它使用crossout标记所有非素数,然后在结果向量上递归。筛子显然不能在向量本身上进行结构递归,但在向量长度上是结构递归的。我想做的是这样的事情: Fixpoint sieve {n:nat} (v:vector bool n) (acc:nat) {struct n} : list nat := match v w

我正试着用Coq写埃拉托什尼的筛子。我有一个函数
crossout:forall{n:nat},vectorbooln->nat->vectorbooln
。当筛子找到一个素数时,它使用
crossout
标记所有非素数,然后在结果向量上递归。筛子显然不能在向量本身上进行结构递归,但在向量长度上是结构递归的。我想做的是这样的事情:

Fixpoint sieve {n:nat} (v:vector bool n) (acc:nat) {struct n} : list nat :=
  match v with
    | [] => Datatypes.nil
    | false :: v' => sieve v' (S acc)
    | true :: v' => Datatypes.cons acc (sieve (crossout v' acc) (S acc))
  end.

但是如果我这样写的话,Coq抱怨说
v'
的长度不是
n
的子项。我知道是这样,但无论我如何构造函数,我似乎无法说服Coq它是这样的。有人知道我怎么做吗?

这是Coq中依赖类型最常见的陷阱之一。直观地说,一旦你在
v
上进行模式匹配,Coq“忘记”该向量的长度实际上是
n
,并失去
v'
的长度与
n
的前身之间的联系。这里的解决方案是应用Adam Chlipala所称的护航模式,并使模式匹配返回一个函数。虽然可以在
v
上进行模式匹配,但我认为在
n
上进行模式匹配更容易:

Require Import Vector.

Axiom crossout : forall {n}, t bool n -> nat -> t bool n.

Fixpoint sieve {n:nat} : t bool n -> nat -> list nat :=
  match n with
    | 0 => fun _ _ => Datatypes.nil
    | S n' => fun v acc =>
                if hd v then
                  Datatypes.cons acc (sieve (crossout (tl v) acc) (S acc))
                else
                  sieve (tl v) (S acc)
  end.
请注意,
sieve
的标题是如何改变的:现在返回类型实际上是一个帮助Coq进行类型推断的函数


有关更多信息,请查看亚当的书:。

非常感谢。我在你发帖前一个小时就知道了,但我不确定这是否是“规范的”解决方案。