import Data.Vect
% default total
% auto_implicits on
{
 a Vect is a List that knows its shape.

 The shape of a data structure is the shadow that it casts:

 [] , [1] , [1 , 2 , 3]

 [] , [■] , [■ , ■ , ■]
 ≅
 Z , S Z , S (S (S Z))

 The shape of a List is its length.
}
 We can do many of the same operations on Lists and Vects:
concat_list : List a > List a > List a
concat_list [] ys = ys
concat_list (x :: xs) ys = x :: concat_list xs ys
concat_vect : Vect m a > Vect n a > Vect (m + n) a
concat_vect [] ys = ys  search
concat_vect (x :: xs) ys = x :: concat_vect xs ys  search
 notice that the programs are exactly the same,
 it's just the types that have changed.
 zipping a pair of lists together is easy if they have the same shape.
 otherwise, we need to either enforce the sameness of shapes
 by trucating the longer one:
zip_list : List a > List b > List (Pair a b)
zip_list [] [] = []
zip_list [] (y :: ys) = []  probably shouldn't happen
zip_list (x :: xs) [] = []  probably shouldn't happen
zip_list (x :: xs) (y :: ys) = (x , y) :: zip_list xs ys
 or return a Maybe List in case the lenghts don't match (exercise).
 Either way, the middle cases are just noise.
 Knowing the shape lets us be more precise:
zip_vect : Vect n a > Vect n b > Vect n (Pair a b)
zip_vect [] [] = []  search
zip_vect (x :: xs) (y :: ys) = (x , y) :: zip_vect xs ys  search
 the programs are basically the same,
 except for the cases that shouldn't happen.
 a path to an element of a list is its index.
 (maybe) replace an element in a list at the given index:
replace_elt_list : (new : a) > (index : Nat) > List a > Maybe (List a)
replace_elt_list new index [] = Nothing
replace_elt_list new Z (x :: xs) = Just (new :: xs)
replace_elt_list new (S n) (x :: xs) =
case replace_elt_list new n xs of
Nothing => Nothing
Just new_tail => Just (x :: new_tail)
 lots of noise dealing with cases we don't want
 replace an element in a list at the given index:
replace_elt_vect : (new : a) > (index : Fin n) > Vect n a > Vect n a
replace_elt_vect new FZ (x :: xs) = new :: xs
replace_elt_vect new (FS n) (x :: xs) = x :: (replace_elt_vect new n xs)
 much shorter and clearer
 if a list doesn't know its shape, then we need to consider cases we don't want
 a list that knows its shape can always forget its shape:
forget_shape : Vect length a > List a
forget_shape [] = []
forget_shape (x :: xs) = x :: forget_shape xs
 but in to learn the shape of a list that doesn't already know it,
 we need to compute it:
learn_shape : (list : List a) > Vect (length list) a
learn_shape [] = []  search
learn_shape (x :: xs) = x :: learn_shape xs  search
 note that we had to do a computation in order to figure out the type of the Vect.