【发布时间】:2023-03-31 09:11:02
【问题描述】:
我是依赖类型的新手(我正在尝试 Idris 和 Coq,尽管它们之间存在很大差异)。
我试图表达以下类型:给定一个类型 T 和一个由 k 个 nats n1, n2, ... nk 组成的序列,一个由长度为 n1, n2, 的 T 的 k 个序列组成的类型。 .. nk 分别.
即k个向量的向量,其长度由参数给定。 这可能吗?
【问题讨论】:
标签: coq dependent-type idris
我是依赖类型的新手(我正在尝试 Idris 和 Coq,尽管它们之间存在很大差异)。
我试图表达以下类型:给定一个类型 T 和一个由 k 个 nats n1, n2, ... nk 组成的序列,一个由长度为 n1, n2, 的 T 的 k 个序列组成的类型。 .. nk 分别.
即k个向量的向量,其长度由参数给定。 这可能吗?
【问题讨论】:
标签: coq dependent-type idris
您可以使用异构列表执行此操作,如下所示。
Require Vector.
Require Import List.
Import ListNotations.
Inductive hlist {A : Type} (B : A -> Type) : list A -> Type :=
| hnil : hlist B []
| hcons : forall a l, B a -> hlist B l -> hlist B (a :: l).
Definition vector_of_vectors (T : Type) (l : list nat) : Type :=
hlist (Vector.t T) l.
那么如果l 是您的长度列表,那么vector_of_vectors T l 的类型将是您描述的类型。
比如我们可以构造一个vector_of_vectors bool [2; 0; 1]的元素:
Section example.
Definition ls : list nat := [2; 0; 1].
Definition v : vector_of_vectors bool ls :=
hcons [false; true]
(hcons []
(hcons [true] hnil)).
End example.
此示例使用一些符号表示您可以这样设置的向量:
Arguments hnil {_ _}.
Arguments hcons {_ _ _ _} _ _.
Arguments Vector.nil {_}.
Arguments Vector.cons {_} _ {_} _.
Delimit Scope vector with vector.
Bind Scope vector with Vector.t.
Notation "[ ]" := (@Vector.nil _) : vector.
Notation "a :: v" := (@Vector.cons _ a _ v) : vector.
Notation " [ x ] " := (Vector.cons x Vector.nil) : vector.
Notation " [ x ; y ; .. ; z ] " := (Vector.cons x (Vector.cons y .. (Vector.cons z Vector.nil) ..)) : vector.
Open Scope vector.
【讨论】:
Import Vector.VectorNotations.
VectorNotations 有一个错误,即 Vector.nil 的符号被声明为 [] 而不是 [ ],这就是它为 List.nil 声明的方式。这让 Coq 误以为 [] 是一个令牌而不是两个单独的令牌,并干扰了我对 List.nil 使用 [] 的方式。所以我养成了从不导入VectorNotations 的可悲习惯。这个bug已经在master中修复了,总有一天我会改掉这个习惯的。
在 Idris 中,除了创建自定义归纳类型外,我们还可以重用异构向量的标准类型——HVect:
import Data.HVect
VecVec : Vect k Nat -> Type -> Type
VecVec shape t = HVect $ map (flip Vect t) shape
val : VecVec [3, 2, 1] Bool
val = [[False, False, False], [False, False], [False]] -- the value is found automatically by Idris' proof-search facilities
【讨论】:
为了完整起见,这里是 Idris 中的一个解决方案,其灵感来自 James Wilcox 发布的解决方案:
module VecVec
import Data.Vect
data VecVec: {k: Nat} -> Vect k Nat -> (t: Type) -> Type where
Nil : VecVec [] t
(::): {k, n: Nat} -> {v: Vect k Nat} -> Vect n t -> VecVec v t -> VecVec (n :: v) t
val: VecVec [3, 2, 3] Bool
val = [[False, True, False], [False, True], [True, False, True]]
此示例使用括号列表自动转换为基本构造函数 Nil 和 :: 的任何数据类型定义它们。
【讨论】:
VecVec 类型的索引,因为您并没有真正使用变量k:data VecVec : List Nat -> Type -> Type where Nil : VecVec [] t (::) : Vect n t -> VecVec v t -> VecVec (n :: v) t。