module Data.Vect

import Prelude
import Data.Fin

infixr 6 _:-_
data Vect : (0 n : Nat) → (0 a : U) → U where
  VNil :  ∀ a. Vect Z a
  _:-_ : ∀ k a. a → Vect k a → Vect (S k) a

vindex : ∀ n a. Fin n → Vect n a → a
vindex FZ (x :- _) = x
vindex (FS k) (x :- rest) = vindex k rest
vindex () VNil -- Idris doesn't need this hint.

instance ∀ k. Functor (Vect k) where
  map f VNil = VNil
  map f (x :- xs) = f x :- map f xs

toVect : ∀ a. (n : Nat) -> List a -> Maybe (Vect n a)
toVect (S k) (x :: xs) = _:-_ x <$> toVect k xs
toVect Z Nil = Just VNil
toVect _ _ = Nothing

instance ∀ n a. Cast (Vect n a) (List a) where
  cast VNil = Nil
  cast (x :- xs) = x :: cast xs

instance ∀ n a. {{Show a}} → Show (Vect n a) where
  show {n} {a} xs = show $ cast {_} {List a} xs

vIndexes : (n : Nat) → Vect n (Fin n)
vIndexes Z = VNil
vIndexes (S k) = FZ :- map FS (vIndexes k)

vIndexes' : ∀ n a. Vect n a → Vect n (Fin n)
vIndexes' VNil = VNil
vIndexes' ( _ :- xs) = FZ :- map FS (vIndexes' xs)

venum : ∀ n a. Vect n a → Vect n (Fin n × a)
venum VNil = VNil
venum (x :- xs) = (FZ, x) :- map (mapFst FS) (venum xs)

zipVect : ∀ n a b. Vect n a → Vect n b → Vect n (a × b)
zipVect VNil VNil = VNil
zipVect (x :- xs) (y :- ys) = (x,y) :- zipVect xs ys

vset : ∀ n a. Fin n → a → Vect n a → Vect n a
vset () el VNil
vset FZ el (x :- xs) = el :- xs
vset (FS k) el (x :- xs) = x :- vset k el xs

