Types Coq推理行为

Types Coq推理行为,types,coq,agda,dependent-type,Types,Coq,Agda,Dependent Type,我试图用Coq编写以下Agda代码片段 open import Data.Fin using (Fin; suc; zero) open import Data.Nat using (ℕ; suc; zero) thin : {n : ℕ} -> Fin (suc n) -> Fin n -> Fin (suc n) thin zero y = suc y thin (suc x) zero = zero thin (suc x) (suc y) =

我试图用Coq编写以下Agda代码片段

open import Data.Fin using (Fin; suc; zero)
open import Data.Nat using (ℕ; suc; zero)

thin : {n : ℕ} -> Fin (suc n) -> Fin n -> Fin (suc n)
thin zero    y       = suc y
thin (suc x) zero    = zero
thin (suc x) (suc y) = suc (thin x y)
我认为这可以直接翻译成Coq:

Inductive Fin : nat -> Type :=
  | fz {n : nat} : Fin (S n)
  | fs {n : nat} : Fin n -> Fin (S n).

Fixpoint thin {n : nat} (x : Fin (S n)) (y : Fin n) : Fin (S n) :=
  match x, y with
    | fz,      y' => fs y'
    | (fs x'), fz => fz
    | (fs x'), (fs y') => fs (thin x' y')
  end.
但是,这会导致以下错误:

Toplevel input, characters 171-173:
Error:
In environment
thin : forall n : nat, Fin (S n) -> Fin n -> Fin (S n)
n : nat
x : Fin (S n)
y : Fin n
n0 : nat
x' : Fin n0
n1 : nat
y' : Fin n1
The term "x'" has type "Fin n0" while it is expected to have type
 "Fin (S ?n1)".

我相信Coq应该能够计算出隐式参数
n
,所以我不知道发生了什么。我认为我不知道AGDA和Coq的类型系统在前一个类型检查中的区别。

< P>当有依赖类型的模式匹配时,Coq通常不考虑上下文中变量和分支中引入的变量之间的本质关系。 最简单的解决方案是在证明模式下定义函数,至少要理解发生了什么

这使得:

Fixpoint thin {n : nat} (x : Fin (S n)) (y : Fin n) : Fin (S n).
Proof.
  remember (S n) as n1. (* trick to keep the information when destructing *)
  destruct x; apply eq_add_S in Heqn1; subst n0.
  - apply fs. assumption.
  - destruct y.
    + apply fz.
    + apply fs. apply thin; assumption.
Defined. (* to create a transparent constant, as given by a classic Fixpoint *)
然后可以打印该值并读取lambda术语,以了解如何直接定义它。这可以提供:

Fixpoint thin {n : nat} (x : Fin (S n)) (y : Fin n) : Fin (S n) :=
  match x as x0 in Fin k return k = S n -> Fin (S n) with
  | fz => fun _ => fs y
  | fs x' =>
      fun H => match y as y0 in Fin l return n = l -> Fin (S n) with
      | fz => fun _ => fz
      | fs y' => fun H' =>
          fs (eq_rec_r (fun x => Fin x)
                       (thin (eq_rec_r _
                                (eq_rec_r _ x' (eq_add_S _ _ (eq_sym H)))
                                (eq_sym H'))
                              y')
                       H')
      end eq_refl
  end eq_refl.
模式匹配的
return
子句用于解决上述问题:它们连接分支中引入的变量和上下文中的变量。这里将对此进行更深入的讨论:


还要注意的是,几周前在coq俱乐部的邮件列表中讨论过这种特殊的归纳类型。请参阅。

如果您想坚持使用与Agda非常相似的语法,可以使用Sozeau的插件。您将能够编写:

Require Import Equations.

Inductive Fin : nat -> Type :=
  | fz {n : nat} : Fin (S n)
  | fs {n : nat} : Fin n -> Fin (S n).

Lemma FinO_elim : Fin O -> False.
Proof.
inversion 1.
Qed.

Equations thin {n : nat} (x : Fin (S n)) (y : Fin n) : Fin (S n)
:= thin {n:=O}     _      y      :=! y (* y is uninhabited *)
;  thin fz     y      := fs y
;  thin (fs x) fz     := fz
;  thin (fs x) (fs y) := fs (thin x y)
.

You can also remove the first dead-code clause which is automatically inferred.

Coq中的模式匹配不如Agda中的强大。IIRC,您可以通过递归定义
Fin
来帮助Coq。试着翻译。这很有帮助,谢谢!我应该先读完Chlipala的书,然后才真正尝试在Coq里做事。我还有一个问题:在证明模式下定义函数被认为是不好的做法吗?@cauliflower,我真的不知道。通常,我这样做是为了检查lambda项并自己编写。无论如何,我尝试使用低层次的策略来创建一个可读的lambda术语。像
inversion
这样的策略创建像
inversion
这样的策略创建非自然术语,应该避免。也许其他用户对这个问题有更强烈的看法。@cauliflower我一直都是在证明模式下编写函数的。一个常见的想法是使用Coq的推理和战术能力以自动化的方式合成术语。然而,这并不一定是大多数用户所习惯的。你使用什么版本的Coq和插件?使用
n
作为隐式参数,我有一个奇怪的错误“非穷举模式匹配”。我通过opam安装了coq 8.5~beta2,coq:方程0.9~beta2。顺便说一句,如果仔细观察
thin
的类型,您会发现
n
是一个隐式参数。然而,在定义函数时,等式似乎要求所有隐式参数都显式化。对于Coq 8.5.dev和等式8.5.dev,相同的示例不起作用。我看到
n
被声明为隐式的,但这正是问题所在。如果
n
不是隐式的(并添加到递归调用中),则接受该示例。