I am having some trouble with the code below. Essentially I want to create a slice type. The motivation comes from Python, where a slice is [start:end:step]
, used for slicing a sublist out of a list. This is conceptually the same as a sequence of indices [start, start+step, start+2*step, ..., end]
.
The way I've tried to capture it is Slice n
can be applied to a Vect (n+m) a
. The basic constructor FwdS
will create a slice with a non-zero step (proof stepNZ). The SLen
constructor will increment an existing slice's Vect
size requirement by its step
(computed using stepOf
). Similarly SStart
increments a slice's Vect
size requirement by 1.
Then the final value conceptually corresponds to:
start := # of SStart in slice
stop := start + (# of SLen) * step
step := constructor argument in FwdS
If the slice is [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
The trouble is in the last pattern. I'm not sure what the issue is - if I try to case split on xs
I get both []
and (_::_)
impossible. Ideally I'd like to have that case read something like this:
select (SLen slice) (x :: xs) = let rec = drop (stepOf slice) (x::xs)
in x :: (select slice rec)
and have Idris recognize that if the first argument is an SLen
constructor, the second argument cannot be []
. My intuition is that at the SLen
level, Idris does not understand it already has a proof that stepOf slice
is not Z
. But I'm not sure how to test that idea.