我在使用下面的代码时遇到了一些问题。基本上我想创建一个切片类型。动机来自Python,其中切片为[start:end:step]
,用于从列表中切割子列表。这在概念上与索引序列[start, start+step, start+2*step, ..., end]
相同。
我尝试捕获它的方式Slice n
可以应用于Vect (n+m) a
。基本构造函数FwdS
将创建一个非零步骤的切片(证明步骤NZ)。 SLen
构造函数将按其Vect
(使用step
计算)增加现有切片的stepOf
大小要求。同样,SStart
会将切片的Vect
尺寸要求增加1。
然后,最终值在概念上对应于:
start := # of SStart in slice
stop := start + (# of SLen) * step
step := constructor argument in FwdS
如果切片是[start:stop:step]
。
mutual
data Slice : Nat -> Type where
FwdS : (step : Nat) -> {stepNZ : Not (step = Z)} -> Slice Z
SLen : (x : Slice len) -> Slice (len + (stepOf x))
SStart : Slice len -> Slice (S len)
stepOf : Slice n -> Nat
stepOf (FwdS step) = step
stepOf (SLen slice) = stepOf slice
stepOf (SStart slice) = stepOf slice
length : Slice n -> Nat
length (FwdS step ) = Z
length (SLen slice) = let step = stepOf slice
len = length slice
in len + step
length (SStart slice) = length slice
select : (slice: Slice n) -> Vect (n+m) a -> Vect (length slice) a
select (FwdS step) xs = []
select (SStart slice) (x :: xs) = select slice xs
select (SLen slice) (xs) = ?trouble
麻烦在于最后一种模式。我不确定问题是什么 - 如果我尝试在xs
上进行案件分割,我就无法[]
和(_::_)
。理想情况下,我希望将此案例改为:
select (SLen slice) (x :: xs) = let rec = drop (stepOf slice) (x::xs)
in x :: (select slice rec)
让Idris认识到如果第一个参数是SLen
构造函数,则第二个参数不能是[]
。我的直觉是,在SLen
级别,Idris不理解它已经证明stepOf slice
不是Z
。但我不确定如何测试这个想法。
答案 0 :(得分:1)
我的直觉是,在SLen级别,Idris不明白它已经有一个证明stepOf切片不是Z.
你是对的。使用:t trouble
,您会发现编译器没有足够的信息来推断(plus (plus len (stepOf slice)) m)
不是0。
a : Type
m : Nat
len : Nat
slice : Slice len
xs : Vect (plus (plus len (stepOf slice)) m) a
--------------------------------------
trouble : Vect (plus (length slice) (stepOf slice)) a
您必须解决两个问题:为某些stepOf slice
S k
获取k
为getPrf : (x : Slice n) -> (k ** stepOf x = (S k))
的证明,然后将Vect (plus (plus len (stepOf slice)) m) a
重写为类似Vect (S (plus k (plus len m))) a
xs
所以编译器至少可以知道这个select
不是空的。但是从那以后它并不容易。 : - )
基本上每当你有一个在参数中使用函数的函数时,你可能会将这些信息重写为该类型。与length slice
SLen
或stepOf x
data Slice : (start : Nat) -> (len : Nat) -> (step : Nat) -> (cnt : Nat) -> Type where
FwdS : (step : Nat) -> Slice Z Z step Z
SLen : Slice Z len step cnt -> Slice Z (S step + len) step (S cnt)
SStart : Slice start len step cnt -> Slice (S start) len step cnt
一样。以下是一个示例实现:
len
您从中获益良多:您可以直接访问参数step
和length
,而无需先验证函数stepOf
和SLen $ SStart $ SLen $ SStart $ FwdS 3
。您还可以更好地控制允许的数据。例如,在你的定义中select
本来是有效的,混合步骤并开始增量。
select : Slice start len step cnt -> Vect (start + len + m) a -> Vect cnt a
select (FwdS k) xs = []
select (SStart s) (x :: xs) = select s xs
select (SLen s) [] impossible
select (SLen s {step} {len} {cnt}) (x::xs) {m} {a} =
let is = replace (sym $ plusAssociative step len m) xs {P=\t => Vect t a} in
(x :: select s (drop step is))
可能如下所示:
select : Slice start len step cnt -> Vect (len + start + m) a -> Vect cnt a
如果您想要一个带证明的练习,您可以尝试实施start + len
,以便切换> select (SStart $ SLen $ SLen $ FwdS 3) [0,1,2,3,4,5,6,7,8,9]
[1, 5] : Vect 2 Integer
。
从4开始,将两个元素从1开始:
http://www.example.com/service-name-1
http://www.example.com/service-name-2