{-# OPTIONS --overlapping-instances --instance-search-depth=10 #-}

module Example.Hefty.Lambda+State where

open import Function hiding (_↣_; _⟶_)
open import Level renaming (zero to ℓ0) using ()
open import Data.Nat
open import Data.Universe renaming (Universe to Univ)
private Universe = Univ ℓ0 ℓ0
open Univ  ...  renaming (U to Ty; El to ⟦_⟧)
open import Relation.Binary.PropositionalEquality

open import Free hiding (_>>=_; _>>_)
open import Free.State 
open import Free.Nil

open import Hefty hiding (_>>=_; _>>_)
open import Hefty.Lift
open import Hefty.Lambda
open import Hefty.Nil

open import Function.Construct.Identity using (↔-id)


{-
A universe of types polymorphic test program
-}

module _  u : LamUniverse  {num : Ty}
          iso₁ :  num     where

  open import Hefty using (_>>=_; _>>_)
  open Inverse  ... 

  ex : Hefty (Lam  Lift State  Lift Nil) 
  ex = do
     put 1
    f  ‵lam  x  do
          n₁  ‵var x
          n₂  ‵var x
          pure (from ((to n₁) + (to n₂))))
    v  ‵app f incr
    pure (to v)
    where incr = do s₀   get;  put (s₀ + 1); s₁   get; pure (from s₁)

{-
A call-by-value interpretation of the universe of types
-}

module CBVInterpretation where

  {-
  A universe of types with functions and numbers
  -}

  data Type : Set where
    _⟶_ : (t₁ t₂ : Type)  Type
    num : Type

  private instance
    CBVUniverse : Universe
    Ty  CBVUniverse  = Type
    ⟦_⟧  CBVUniverse  (t  t₁)  =  t   Free (State  Nil)  t₁ 
    ⟦_⟧  CBVUniverse  num       = 


    {-
    The call-by-value interpretation adheres to the LamUniverse interface from
    `Hefty.Lambda`
    -}

    iso-num :    num 
    iso-num = ↔-id _

    iso-fun : {t₁ t₂ : Type}
             ( t₁   Free (State  Nil)  t₂ )   t₁  t₂ 
    iso-fun = ↔-id _

    iso-c : {t : Type}   t    id t 
    iso-c = ↔-id _

    LamCBVUniverse : LamUniverse
    u     LamCBVUniverse  = CBVUniverse
    _↣_   LamCBVUniverse  = _⟶_
    c     LamCBVUniverse  = id


  {-
  Automatic elaboration
  -}

  elab-cbv : Elab (Lam  Lift State  Lift Nil) (State  Nil)
  elab-cbv = auto-elab

  {-
  The program evaluates using a call-by-value interpretation
  -}
  test-ex-cbv : un ((given hSt handle (elab elab-cbv ex)) 0)  4
  test-ex-cbv = refl


{-
A call-by-name interpretation of the universe of types
-}

module CBNInterpretation where

  {-
  A universe of types with functions, numbers, and thunks (suspended computations)
  -}

  data Type : Set where
    _⟶_ : (t₁ t₂ : Type)    Type
    num  :                     Type
    susp : Type               Type

  private instance
    CBNUniverse : Universe
    Ty  CBNUniverse  = Type
    ⟦_⟧  CBNUniverse  (t  t₁)  =  t   Free (State  Nil)  t₁ 
    ⟦_⟧  CBNUniverse  num        = 
    ⟦_⟧  CBNUniverse  (susp t)   = Free (State  Nil)  t 


    {-
    The call-by-name interpretation adheres to the LamUniverse interface from
    `Hefty.Lambda`
    -}

    iso-num :    num 
    iso-num = ↔-id _

    iso-fun : {t₁ t₂ : Type}
             ( t₁   Free (State  Nil)  t₂ )   t₁  t₂ 
    iso-fun = ↔-id _

    iso-susp : {t : Ty}
              Free (State  Nil)  t    susp t 
    iso-susp = ↔-id _

    LamCBNUniverse : LamUniverse
    u  LamCBNUniverse  = CBNUniverse
    _↣_  LamCBNUniverse  = _⟶_
    c  LamCBNUniverse  = susp


  {-
  Automatic elaboration
  -}

  elab-cbn : Elab (Lam  Lift State  Lift Nil) (State  Nil)
  elab-cbn = auto-elab


  {-
  The program evaluates using a call-by-value interpretation
  -}
  test-ex-cbv : un ((given hSt handle (elab elab-cbn ex)) 0)  5
  test-ex-cbv = refl