packages feed

prob-fx-0.1.0.0: src/Effects/ObsReader.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators, TypeApplications #-}
{-# LANGUAGE AllowAmbiguousTypes #-}

{- | An effect for reading observable variables from a model environment -}

module Effects.ObsReader (
    ObsReader(..)
  , ask
  , handleRead) where

import Prog ( call, discharge, Member, Prog(..) )
import Env ( Env, ObsVar, Observable(..) )
import Util ( safeHead, safeTail )

-- | The effect for reading observed values from a model environment @env@
data ObsReader env a where
  -- | Given variable @x@ is assigned a list of type @[a]@ in @env@, attempt to retrieve its head value.
  Ask :: Observable env x a       
    => ObsVar x                 -- ^ Variable @x@ to read from
    -> ObsReader env (Maybe a)  -- ^ The head value from @x@'s list

-- | Retrieve the first value from the trace of an observable variable if it exists
ask :: forall env es x a. (Member (ObsReader env) es, Observable env x a) =>  ObsVar x -> Prog es (Maybe a)
ask x = call (Ask @env x)

-- | Handle the @Ask@ requests of observable variables
handleRead :: 
  -- | Initial model environment
     Env env 
  -> Prog (ObsReader env ': es) a 
  -> Prog es a
handleRead env (Val x) = return x
handleRead env (Op op k) = case discharge op of
  Right (Ask x) ->
    let vs       = get x env
        maybe_v  = safeHead vs
        env'     = set x (safeTail vs) env
    in  handleRead env' (k maybe_v)
  Left op' -> Op op' (handleRead env . k)