依赖类型:在归纳类型中强制执行全局属性

时间:2017-08-20 17:43:11

标签: dependent-type idris

我有以下归纳类型MyVec

import Data.Vect

data MyVec: {k: Nat} -> Vect k Nat -> Type where
  Nil: MyVec []
  (::): {k, n: Nat} -> {v: Vect k Nat} -> Vect n Nat -> MyVec v -> MyVec (n :: v)

-- example:
val: MyVec [3,2,3]
val = [[2,1,2], [0,2], [1,1,0]]

即,类型指定MyVec内所有向量的长度。

问题是,valk = 3 kMyVec内的向量数量,但是ctor ::不知道这个事实。它首先会使用MyVec构建k = 1,然后使用2,最后使用3。这使得无法根据值的最终形状定义约束。

例如,我不能将值限制为严格小于k。接受Vect Fin (S k)代替Vect Nat的{​​{1}}将排除一些有效值,因为最后一个向量(第一个由ctor插入)将&#34 ;知道"较小的k值,因此是一个更严格的约束。

或者,另一个例子,我不能强制执行以下约束:位置i处的向量不能包含数字。因为ctor不知道容器中矢量的最终位置(如果已知k的最终值,将会自动知道)。

所以问题是,我如何强制执行这样的全局属性?

1 个答案:

答案 0 :(得分:4)

有(至少)两种方法可以执行此操作,这两种方法都可能需要跟踪其他信息才能检查属性。

data定义

中强制执行属性

执行所有元素< k

  

我无法将值限制为严格小于k。接受Vect Fin (S k)代替Vect的{​​{1}}会排除某些有效值......

你是对的,只是将Nat的定义更改为包含MyVect就不对了。

但是,通过将Vect n (Fin (S k))概括为多态来解决这个问题并不难,如下所述。

MyVect

此解决方案的关键是在data MyVec: (A : Type) -> {k: Nat} -> Vect k Nat -> Type where Nil: {A : Type} -> MyVec A [] (::): {A : Type} -> {k, n: Nat} -> {v: Vect k Nat} -> Vect n A -> MyVec A v -> MyVec A (n :: v) val : MyVec (Fin 3) [3,2,3] val = [[2,1,2], [0,2], [1,1,0]] 的定义中将矢量类型与k分开,然后在顶层使用&{34;全局值{{1约束矢量元素的类型。

MyVec位置执行向量不包含k

  

我无法强制执行位置i处的向量不能包含数字i,因为构造函数不知道容器中向量的最终位置。

同样,解决方案是概括i定义以跟踪必要的信息。在这种情况下,我们想要跟踪 final 值中的当前位置。我称之为i。然后我概括data以传递当前索引。最后,在顶层,我传入一个谓词,强制该值不等于索引。

index

事后

执行属性

另一种有时更简单的方法是立即在A定义中强制执行该属性,而是在事后编写谓词。

执行所有元素data MyVec': (A : Nat -> Type) -> (index : Nat) -> {k: Nat} -> Vect k Nat -> Type where Nil: {A : Nat -> Type} -> {index : Nat} -> MyVec' A index [] (::): {A : Nat -> Type} -> {k, n, index: Nat} -> {v: Vect k Nat} -> Vect n (A index) -> MyVec' A (S index) v -> MyVec' A index (n :: v) val : MyVec' (\n => (m : Nat ** (n == m = False))) 0 [3,2,3] val = [[(2 ** Refl),(1 ** Refl),(2 ** Refl)], [(0 ** Refl),(2 ** Refl)], [(1 ** Refl),(1 ** Refl),(0 ** Refl)]]

例如,我们可以编写一个谓词来检查所有向量的所有元素是否都是data,然后断言我们的值是否具有此属性。

< k

< k位置执行向量不包含wf : (final_length : Nat) -> {k : Nat} -> {v : Vect k Nat} -> MyVec v -> Bool wf final_length [] = True wf final_length (v :: mv) = isNothing (find (\x => x >= final_length) v) && wf final_length mv val : (mv : MyVec [3,2,3] ** wf 3 mv = True) val = ([[2,1,2], [0,2], [1,1,0]] ** Refl)

同样,我们可以通过检查它来表达属性,然后声明该值具有属性。

i
相关问题