open import Level

open import Data.Unit
open import Data.Product

open import Chapter2.Logic

open import Chapter5.IDesc
open import Chapter5.IDesc.Fixpoint
open import Chapter5.IDesc.Lifting
open import Chapter5.IDesc.Induction


module Chapter6.IDesc.InitialAlgebra 
         { k : Level}
         {I : Set k}{X : I  Set }
         (D : func  I I)
         (α : {i : I}   D ⟧func X i  X i)
       where


fold : {i : I}  μ D i  X i
fold x = lower (induction D  {i} _  Lift {}{k} (X i))
                    {i}{xs} ih  lift (α (replace (func.out D i) xs ih)))
                   x)
  where replace : (D' : IDesc  I)(xs :  D'  (μ D)) 
                  (ih : [ D' ]^h  {i} _  Lift (X i)) xs) 
                   D'  X
        replace (`var i) xs (lift x) = x
        replace `1 (lift tt) (lift tt) = lift tt
        replace (D  D') (xs , xs') (x , x') = replace D xs x , replace D' xs' x'
        replace ( n T) (k , xs) ih = k , replace (T k) xs ih
        replace ( S T) (s , xs) ih = s , replace (T s) xs ih
        replace ( S T) xs ih = λ s  replace (T s) (xs s) (ih s)