我正在研究Coq中我自己的向量实现,而且我遇到了一个奇怪的问题。
到目前为止,这是我的代码:
Inductive Fin : nat -> Type :=
|FZ : forall n, Fin (S n)
|FS : forall n, Fin n -> Fin (S n).
Definition emptyf(A : Type) : Fin 0 -> A.
intro e; inversion e.
Defined.
Inductive Vec(A : Type) : nat -> Type :=
|Nil : Vec A 0
|Cons : forall n, A -> Vec A n -> Vec A (S n).
Definition head(A : Type)(n : nat)(v : Vec A (S n)) : A :=
match v with
|Cons a _ => a
end.
Definition tail(A : Type)(n : nat)(v : Vec A (S n)) : Vec A n :=
match v with
|Cons _ w => w
end.
Fixpoint index(A : Type)(n : nat) : Vec A n -> Fin n -> A :=
match n as n return Vec A n -> Fin n -> A with
|0 => fun _ i => emptyf _ i
|S m => fun v i => match i with
|FZ _ => head v
|FS j => index (tail v) j
end
end.
最高tail
的所有内容编译都很好,但是当我尝试编译index
时,我收到以下错误:
Error:
In environment
index : forall (A : Type) (n : nat), Vec A n -> Fin n -> A
A : Type
n : nat
m : nat
v : Vec A (S m)
i : Fin (S m)
n0 : nat
j : Fin n0
The term "j" has type "Fin n0" while it is expected to have type "Fin m".
显然,罪魁祸首是Coq引入新变量n0
而不是j
类型Fin m
,即使这是j
唯一可能的类型会导致从i
构建j
。知道为什么会这样,以及我如何能够解决这个问题?
答案 0 :(得分:3)
请注意,您不需要针对n
进行模式匹配,而只需针对Fin n
类型的参数进行模式匹配。结果定义更简单。
Fixpoint index {A:Type} {n:nat} (i:Fin n) : Vec A n -> A :=
match i in Fin n0 return Vec A n0 -> A with
| FZ => fun v => head v
| FS j => fun v => index j (tail v)
end.
Coq实际上足以猜测注释。
Fixpoint index {A:Type} {n:nat} (i:Fin n) : Vec A n -> A :=
match i with
| FZ => fun v => head v
| FS j => fun v => index j (tail v)
end.
答案 1 :(得分:2)
我发现Vec
和Fin
一般很难使用,所以我这些天使用math-comp中的'I_n
和n.-tuples T
,这些只是自然而已附有无关证据的清单。但是,如果您想继续复杂模式匹配的乐趣,您可以尝试定义更强大的模式匹配原则:
Definition fin_case T m (i : Fin m) : T -> (Fin (pred m) -> T) -> T :=
match i with
| FZ _ => fun fn fz => fn
| FS _ j => fun fn fz => fz j
end.
一旦你有fin_case
,你的函数定义就可以了:
Fixpoint index (A : Type) (n : nat) : Vec A n -> Fin n -> A :=
match n as n return Vec A n -> Fin n -> A with
| 0 => fun _ i => emptyf _ i
| S m => fun v i => fin_case i (head v) (index (tail v))
end.
答案 2 :(得分:2)
使用 match i in Fin (S n0) return n0 = m -> A with
... => fun H : n0 = m => ...
end eq_refl
时,您可能会丢失信息。我使用convoy pattern将信息返回到上下文中。
n0 = m
使Coq能够将信息(match H with ... end)
放入上下文中。它作为函数参数发送到match子句中。要在类型检查中使用它,我使用Fin n0 = Fin m
,以便Coq理解Fixpoint index(A : Type)(n : nat) : Vec A n -> Fin n -> A :=
match n as n return Vec A n -> Fin n -> A with
|0 => fun _ i => emptyf _ i
|S m => fun v i =>
match i in Fin (S n') return n' = m -> A with
|FZ _ => fun _ => head _ _ v
|FS _ j => fun H => index (tail v) (match H with eq_refl _ => j end)
end eq_refl
end.
。
这是解决方案。
refine
当类型检查不能理解两件事情是相同的时,通常护航模式可以帮助您将信息传递到上下文中。我还建议使用public function connect(UserInterface $user, UserResponseInterface $response)
逐步建立术语。它让您可以看到上下文中的信息。
答案 3 :(得分:2)
只是为了添加其他答案,基于策略的解决方案:
Fixpoint index (A : Type) (n : nat) (v : Vec A n) (i : Fin n) : A.
destruct v as [| n h tl].
- exact (emptyf A i).
- inversion i as [ | ? i'].
+ exact h.
+ exact (index _ _ tl i').
Defined.
inversion
策略处理"信息丢失"。如果您尝试Print index.
,结果不会很漂亮,但Coq基本上使用了@larsr提到的护航模式。
请注意,此方法不会在n
上使用模式匹配。它改为对矢量参数进行模式匹配,这就是为什么它不需要head
和tail
函数。