{-# OPTIONS --safe --sized-types #-}

module StateOfTheArt.CDMM where

open import Size
open import Data.Empty
open import Data.Bool
open import Data.Nat using ( ; suc)
open import Data.Unit
open import Data.Product as Prod
open import Function
open import Relation.Unary
open import Relation.Binary.PropositionalEquality hiding ([_])


data Desc (I J : Set) : Set₁ where
   : (A : Set)  (A  Desc I J)  Desc I J
  `X : J  Desc I J  Desc I J
  `∎ : I  Desc I J

private
  variable
    I J : Set
    i : I
    j : J
    d : Desc I J
    X Y : J  Set
    s : Size
    A B : Set

`K : Set  I  Desc I J
`K A i =  A  _  `∎ i)

infixr 5 _`+_

_`+_ : Desc I J  Desc I J  Desc I J
d `+ e =  Bool $ λ { true   d ; false  e }

⟦_⟧ : Desc I J  (J  Set)  (I  Set)
  A d   X i = Σ[ a  A ] ( d a  X i)
 `X j d   X i = X j ×  d  X i
 `∎ i′    X i = i  i′

fmap : (d : Desc I J)  ∀[ X  Y ]  ∀[  d  X   d  Y ]
fmap ( A d)  f (a , v)  = (a , fmap (d a) f v)
fmap (`X j d)  f (r , v)  = (f r , fmap d f v)
fmap (`∎ i)    f t        = t

data μ (d : Desc I I) : Size  I  Set where
  `con :  d  (μ d s) i  μ d ( s) i

fold : (d : Desc I I)  ∀[  d  X  X ]  ∀[ μ d s  X ]
fold d alg (`con t) = alg (fmap d (fold d alg) t)

finD : Desc  
finD =    $ λ index 
         Bool $ λ isZero  if isZero
        then `∎ (suc index)
        else `X index (`∎ (suc index))

fin :   Set
fin = μ finD 

fin0-elim : fin 0  
fin0-elim (`con (_ , true , ()))
fin0-elim (`con (_ , false , _ , ()))

fz :  n  fin (suc n)
fz n = `con (n , true , refl)

fs :  n  fin n  fin (suc n)
fs n k = `con (n , false , k , refl)

listD : Set  Desc  
listD A =   Bool $ λ isNil 
           if isNil then `∎ tt
           else  A  _  `X tt (`∎ tt))

List : Set  Set
List A = μ (listD A)  tt

infixr 10 _∷_

pattern []'  = (true , refl)
pattern []   = `con []'

pattern _∷'_ x xs  = (false , x , xs , refl)
pattern _∷_ x xs   = `con (x ∷' xs)

example : List (List Bool)
example = (false  [])  (true  [])  []

vecD : Set  Desc  
vecD A =   Bool $ λ isNil 
          if isNil then `∎ 0
          else    n   A  _  `X n (`∎ (suc n))))

Vec : Set    Set
Vec A = μ (vecD A) 

foldr : (A  B  B)  B  List A  B
foldr c n = fold (listD _) $ λ where
  []'           n
  (hd ∷' rec)   c hd rec

_++_ : List A   List A  List A
_++_ = foldr  hd rec  hd ∷_  rec) id

flatten : List (List A)  List A
flatten = foldr _++_ []

test : flatten example  false  true  []
test = refl