Зависимые типы: вектор векторов
Я новичок в зависимых типах (я пробую и Idris, и Coq, несмотря на их большие различия).
Я пытаюсь выразить следующий тип: задан тип T и последовательность k НАТОВ n1, n2, ... nk, тип, состоящий из K последовательностей T длиной n1, n2, ... nk соответственно .
, то есть вектор из k векторов, длины которых задаются параметром. Возможно ли это?
3 ответа:
Вы можете сделать это с гетерогенным списком следующим образом.
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.
В 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
Для полноты, вот решение в Идрисе, вдохновленное тем, что написал Джеймс Уилкокс:
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
и::
любого типа данных, определяющего их.