module Chapter8.AlgebraicOrnament.Examples.Expr where

open import Level hiding (zero ; suc)

open import Data.Unit
open import Data.Nat
open import Data.Fin hiding (_+_ ; lift)
open import Data.Product

open import Relation.Binary.PropositionalEquality

open import Chapter5.IDesc
open import Chapter5.IDesc.Fixpoint
open import Chapter5.IDesc.InitialAlgebra
open import Chapter5.IDesc.Induction

import  Chapter8.AlgebraicOrnament

ExprD : func _  
ExprD = func.mk λ _  
         2  { zero    λ _  `1 
                ; (suc zero)  `var tt  `var tt  `1 
                ; (suc (suc ())) })

Expr : Set
Expr = μ ExprD tt

const :   Expr
const n =  zero , n , lift tt 

add : Expr  Expr  Expr
add m n =  suc zero , m , n , lift tt 

α : Alg ExprD  _  )
α {tt} (zero , n , lift tt) = n
α {tt} (suc zero , el , er , lift tt) = el + er
α {tt} (suc (suc ()) , _)

open Chapter8.AlgebraicOrnament.Func ExprD α

ExprSem :   Set
ExprSem n = μ algOrnD (tt , n)

constS : (n : )  ExprSem n
constS n =  (zero , n , lift tt) , refl , lift tt 

addS : ∀{m n}  ExprSem m  ExprSem n  ExprSem (m + n)
addS {m}{n} e₁ e₂ =  (suc zero , m , n , lift tt) , refl , e₁ , e₂ , lift tt 

private
  record ⟨optimise-0+_⟩ {n : }(e : ExprSem n) : Set where
    constructor return
    field
      call : ExprSem n
  open ⟨optimise-0+_⟩ public

  β : DAlg algOrnD  e  ⟨optimise-0+ e ) 
  β {tt , .n} {(zero , n , lift tt) , refl , lift tt} (lift tt) = return (constS n)
  β {tt , .n} {(suc zero , zero , n , lift tt) , refl ,  (zero , .0 , lift tt) , refl , lift tt  , e₂ , lift tt} (optL , optR , lift tt) = return (call optR)
  β {tt , .(m + n)} {(suc zero , m , n , lift tt) , refl , e₁ , e₂ , lift tt} (optL , optR , lift tt) = return (addS e₁ e₂)
  β {_} {(suc (suc ()) , _) , _ , _} _

  optimise : ∀{n}  (e : ExprSem n)  ⟨optimise-0+ e 
  optimise = induction algOrnD  e  ⟨optimise-0+ e ) β

optimise-0+ : ∀{n}  (e : ExprSem n)  ExprSem n
optimise-0+ e = call (optimise e)

module Test where

  test-0+ : ∀{k n}  optimise-0+ (addS {0}{k} (constS 0) n)  optimise-0+ n
  test-0+ = refl