{-# OPTIONS --safe #-}

--------------------------------------------------------------------------------
-- Vectors implemented as functions from Fins
--------------------------------------------------------------------------------

module Data.Vec where

open import Prelude hiding (tabulate)

Vec : Type a    Type a
Vec A n = (i : Fin n)  A

private variable n m : 

infixr 5 _◂_
_◂_ : A  Vec A n  Vec A (suc n)
(x  xs) zero    = x
(x  xs) (suc i) = xs i

⟅⟆ : Vec A zero
⟅⟆ ()

vec-foldr : (N :   Type b)  
            (∀ {n}  A  N n  N (suc n)) 
            N zero 
            Vec A n  N n
vec-foldr {n = zero}  N f b xs = b
vec-foldr {n = suc n} N f b xs = f (xs zero) (vec-foldr N f b (xs  suc))

◂-id : (xs : Vec A (suc n))  xs zero  xs  suc  xs
◂-id xs = funExt λ { zero  refl ; (suc i)  refl }

singleton-id : (x : A)  x  ⟅⟆  const x
singleton-id _ = funExt λ { zero  refl }

head-singleton-id : (xs : Vec A 1)  xs zero  ⟅⟆  xs
head-singleton-id _ = funExt λ { zero  refl }

ConcreteVec : Type a    Type a
ConcreteVec A zero    = Poly-⊤
ConcreteVec A (suc n) = A × ConcreteVec A n

tabulate : Vec A n  ConcreteVec A n
tabulate {n = zero}  xs = Poly-tt
tabulate {n = suc n} xs = xs 0 , tabulate (xs  suc)

Curryⁿ : (n : )  (A : Type a)  (P : ConcreteVec A n  Type a)  Type a
Curryⁿ zero    A P = P Poly-tt
Curryⁿ (suc n) A P = (x : A)  Curryⁿ n A (P  _,_ x)

uncurryⁿ :  {n} {P : ConcreteVec A n  Type a}  Curryⁿ n A P  (xs : Vec A n)  P (tabulate xs)
uncurryⁿ {n = zero}  f xs = f
uncurryⁿ {n = suc n} f xs = uncurryⁿ (f (xs zero)) (xs  suc)