{-# OPTIONS --safe --sized-types #-}
module Generic.Syntax.LetCounter where
open import Algebra
open import Algebra.Structures
open import Data.Bool
open import Data.List.Relation.Unary.All as All
open import Data.Product using (_×_; _,_)
open import Agda.Builtin.List
open import Agda.Builtin.Equality
open import Relation.Unary
open import Function
open import Data.Var
open import Generic.Syntax
open import Generic.Syntax.LetBinder using (Let)
module _ {a} {A : Set a} (expensive : A) where
  _ : A × A
  
  _ =  let x = expensive  in
       let y = (x , x)    in
       y
  _ : A
  
  _ =  let x = expensive  in
       let y = (x , x)    in
       x
data Counter : Set where
  zero  : Counter
  one   : Counter
  many  : Counter
_+_ : Counter → Counter → Counter
zero  + n     = n
m     + zero  = m
_     + _     = many
_*_ : Counter → Counter → Counter
zero  * n     = zero
m     * zero  = zero
one   * n     = n
m     * one   = m
many  * many  = many
module _ {I : Set} where
  private
    variable
      σ : I
  Count : List I → Set
  Count = All (const Counter)
  zeros : ∀[ Count ]
  zeros {[]}     = []
  zeros {σ ∷ Γ}  = zero ∷ zeros
  fromVar : ∀[ Var σ ⇒ Count ]
  fromVar z      = one ∷ zeros
  fromVar (s v)  = zero ∷ fromVar v
  merge : ∀[ Count ⇒ Count ⇒ Count ]
  merge []        []        = []
  merge (m ∷ cs)  (n ∷ ds)  =
    (m + n) ∷ merge cs ds
  control : Counter → ∀[ Count ⇒ Count ]
  control zero  cs = zeros
  control one   cs = cs 
  control many  cs = cs 
  scale : Counter → ∀[ Count ⇒ Count ]
  scale zero  cs = zeros
  scale one   cs = cs
  scale k     cs = map (k *_) cs
  rawMonoid : List I → RawMonoid _ _
  rawMonoid Γ = record
    { Carrier = Count Γ
    ; _≈_     = _≡_
    ; _∙_     = merge
    ; ε       = tabulate (λ _ → zero)
    }
  CLet : Desc I
  CLet = `σ Counter $ λ _ → Let
pattern `IN' e t = (_ , e , t , refl)
pattern `IN  e t = `con (`IN' e t)
module _ {I : Set} {d : Desc I} where
  embed : ∀ {i σ} → ∀[ Tm d i σ ⇒ Tm (d `+ CLet) i σ ]
  embed = map^Tm (MkDescMorphism (true ,_))