packages feed

spectacle-1.0.0: src/Language/Spectacle/Syntax/Env.hs

module Language.Spectacle.Syntax.Env
  ( Env (Env),
    Effect (Get, Put),
    get,
    gets,
    put,
    modify,
    runEnv,
  )
where

import Data.Coerce (coerce)
import Data.Void (absurd)

import Data.Functor.Loom (hoist, runLoom, (~>~))
import Language.Spectacle.Lang (Effect, Lang (Op, Pure, Scoped), Member, decomposeOp, decomposeS, scope)
import Language.Spectacle.RTS.Registers (RuntimeState)
import Language.Spectacle.Syntax.Env.Internal (Effect (Get, Put), Env (Env))

-- ---------------------------------------------------------------------------------------------------------------------

get :: Member Env effs => Lang ctx effs (RuntimeState ctx)
get = scope Get
{-# INLINE get #-}

gets :: Member Env effs => (RuntimeState ctx -> s) -> Lang ctx effs s
gets f = fmap f get
{-# INLINE gets #-}

put :: Member Env effs => RuntimeState ctx -> Lang ctx effs ()
put x = scope (Put x)
{-# INLINE put #-}

modify :: Member Env effs => (RuntimeState ctx -> RuntimeState ctx) -> Lang ctx effs ()
modify f = get >>= put . f
{-# INLINE modify #-}

runEnv :: RuntimeState ctx -> Lang ctx (Env ': effs) a -> Lang ctx effs (RuntimeState ctx, a)
runEnv st = \case
  Pure x -> pure (st, x)
  Op op k -> case decomposeOp op of
    Left other -> Op other (runEnv st . k)
    Right (Env b) -> absurd (coerce b)
  Scoped scoped loom -> case decomposeS scoped of
    Left other -> Scoped other (loom' st)
    Right eff
      | Get <- eff -> runLoom (loom' st) (pure st)
      | Put st' <- eff -> runLoom (loom' st') (pure ())
    where
      loom' st' = loom ~>~ hoist (runEnv st')