我有以下归纳类型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
内所有向量的长度。
问题是,val
将k = 3
k
是MyVec
内的向量数量,但是ctor ::
不知道这个事实。它首先会使用MyVec
构建k = 1
,然后使用2
,最后使用3
。这使得无法根据值的最终形状定义约束。
例如,我不能将值限制为严格小于k
。接受Vect
Fin (S k)
代替Vect
Nat
的{{1}}将排除一些有效值,因为最后一个向量(第一个由ctor插入)将&#34 ;知道"较小的k
值,因此是一个更严格的约束。
或者,另一个例子,我不能强制执行以下约束:位置i处的向量不能包含数字。因为ctor不知道容器中矢量的最终位置(如果已知k的最终值,将会自动知道)。
所以问题是,我如何强制执行这样的全局属性?
答案 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