
module Warshall
  (X   : Set)
  ((≤) : X -> X -> Prop)
  -- and axioms...
  where

id : {A:Set} -> A -> A
id x = x

(∘) : {A B C:Set} -> (B -> C) -> (A -> B) -> A -> C
f ∘ g = \x -> f (g x)

-- Natural numbers --------------------------------------------------------

data Nat : Set where
  zero : Nat
  suc  : Nat -> Nat

(+) : Nat -> Nat -> Nat
zero  + m = m
suc n + m = suc (n + m)

-- Finite sets ------------------------------------------------------------

data Zero : Set where

data Suc (A:Set) : Set where
  fzero_ : Suc A
  fsuc_  : A -> Suc A

mutual

  data Fin (n:Nat) : Set where
    finI : Fin_ n -> Fin n

  Fin_ : Nat -> Set
  Fin_  zero   = Zero
  Fin_ (suc n) = Suc (Fin n)

fzero : {n:Nat} -> Fin (suc n)
fzero = finI fzero_

fsuc : {n:Nat} -> Fin n -> Fin (suc n)
fsuc i = finI (fsuc_ i)

finE : {n:Nat} -> Fin n -> Fin_ n
finE (finI i) = i

infixr 15 ::

-- Vectors ----------------------------------------------------------------

data Nil : Set where
  nil_ : Nil

data Cons (Xs:Set) : Set where
  cons_ : X -> Xs -> Cons Xs

mutual

  data Vec (n:Nat) : Set where
    vecI : Vec_ n -> Vec n

  Vec_ : Nat -> Set
  Vec_  zero   = Nil
  Vec_ (suc n) = Cons (Vec n)

nil : Vec zero
nil = vecI nil_

(::) : {n:Nat} -> X -> Vec n -> Vec (suc n)
x :: xs = vecI (cons_ x xs)

vecE : {n:Nat} -> Vec n -> Vec_ n
vecE (vecI xs) = xs

vec : (n:Nat) -> X -> Vec n
vec  zero   _ = nil
vec (suc n) x = x :: vec n x

map : {n:Nat} -> (X -> X) -> Vec n -> Vec n
map {zero}  f (vecI nil_)         = nil
map {suc n} f (vecI (cons_ x xs)) = f x :: map f xs

(!) : {n:Nat} -> Vec n -> Fin n -> X
(!) {suc n} (vecI (cons_ x _ )) (finI fzero_)    = x
(!) {suc n} (vecI (cons_ _ xs)) (finI (fsuc_ i)) = xs ! i

upd : {n:Nat} -> Fin n -> X -> Vec n -> Vec n
upd {suc n} (finI fzero_)    x (vecI (cons_ _ xs)) = x :: xs
upd {suc n} (finI (fsuc_ i)) x (vecI (cons_ y xs)) = y :: upd i x xs

tabulate : {n:Nat} -> (Fin n -> X) -> Vec n
tabulate {zero}  f = nil
tabulate {suc n} f = f fzero :: tabulate (\x -> f (fsuc x))

postulate
  (===) : {n:Nat} -> Vec n -> Vec n -> Prop


module Proof
    (F : {n:Nat} -> Vec n -> Vec n)
    -- and axioms...
    where

  stepF : {n:Nat} -> Fin n -> Vec n -> Vec n
  stepF i xs = upd i (F xs ! i) xs

  unsafeF' : {n:Nat} -> Nat -> Vec (suc n) -> Vec (suc n)
  unsafeF' zero    = id
  unsafeF' (suc m) = unsafeF' m ∘ stepF fzero

  unsafeF : {n:Nat} -> Vec n -> Vec n
  unsafeF {zero}  = id
  unsafeF {suc n} = unsafeF' (suc n)

  thm : {n:Nat} -> (xs:Vec n) -> F xs === unsafeF xs
  thm = ?

