module Chapter5.IDesc.Tagged where

open import Level
  renaming ( zero to zeroL 
           ; suc to sucL )
open import Function

open import Data.Nat hiding (_⊔_)
open import Data.Fin hiding (lift) renaming (_+_ to _F+_)
open import Data.Vec
open import Data.Product

open import Chapter5.IDesc


tagDesc : ∀( : Level){k}  Set k  Set (k  (sucL ))
tagDesc  {k} I = Tags I × iTags I
  where
    Tags : Set k  Set (k  (sucL ))
    Tags I = Σ[ n   ] (I  Vec (IDesc  I) n)

    iTags : Set k  Set (k  (sucL ))
    iTags I = Σ[ f  (I  ) ] ((i : I)  Vec (IDesc  I) (f i))

-- TODO: Must be part of the stdlib
private
  ⟨_∣_⟩ : ∀{}{A : Set }{m n}  (Fin m  A)  (Fin n  A)  Fin (m + n)  A
  ⟨_∣_⟩ {A = A} {m = m}{n = n} f g k = help m f k
    where help : (m : )  (Fin m  A)  Fin (m + n)  A
          help zero f k = g k
          help (suc m) f zero = f zero
          help (suc m) f (suc k) = help m (f  suc) k

toDesc : ∀{ k}{I : Set k}  tagDesc  I  func  I I 
toDesc ((n , ds) , (f , ids)) =
       func.mk λ i  
          (Lift (Fin (n + f i)))
            λ { (lift k)  
                 (flip lookup) (ds i)  (flip lookup) (ids i)  k }

toTagged : ∀{ k}{I : Set k}  func  I I  tagDesc  I
toTagged d = (( 1 , λ i  func.out d i  []) , (  i  0) , λ i  []))