【问题标题】:Dependent types: Vector of vectors依赖类型:向量的向量
【发布时间】:2023-03-31 09:11:02
【问题描述】:

我是依赖类型的新手(我正在尝试 Idris 和 Coq,尽管它们之间存在很大差异)。

我试图表达以下类型:给定一个类型 T 和一个由 k 个 nats n1, n2, ... nk 组成的序列,一个由长度为 n1, n2, 的 T 的 k 个序列组成的类型。 .. nk 分别.

即k个向量的向量,其长度由参数给定。 这可能吗?

【问题讨论】:

    标签: coq dependent-type idris


    【解决方案1】:

    您可以使用异构列表执行此操作,如下所示。

    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中修复了,总有一天我会改掉这个习惯的。
    • 看起来他们为 Coq 8.6.1 修复了它。
    【解决方案2】:

    在 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
    

    【讨论】:

      【解决方案3】:

      为了完整起见,这里是 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 类型的索引,因为您并没有真正使用变量kdata VecVec : List Nat -> Type -> Type where Nil : VecVec [] t (::) : Vect n t -> VecVec v t -> VecVec (n :: v) t
      最近更新 更多