technique-0.2.5: lib/Technique/Evaluator.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-- At present this is a proof of concept. It might benefit from being
-- converted to a typeclass in the tagless final style.
-- |
-- Given an instantiated Technique Procedure, evalutate it at runtime.
module Technique.Evaluator where
import Control.Monad.IO.Class (MonadIO)
import Control.Monad.Reader.Class (MonadReader (..))
import Control.Monad.Trans.Reader (ReaderT (..))
import Core.Data
import Core.Text
import Data.UUID.Types (UUID)
import Technique.Internal
-- |
-- In order to execute a Procedure we need to supply a Context: an identifier
-- for the event (collection of procedure calls) it is a part of, and the path
-- history we took to get here.
-- TODO values needs to be somewhere, but here?
data Context = Context
{ contextEvent :: UUID,
contextPath :: Rope, -- or a list or a fingertree or...
contextValues :: Map Name Promise -- TODO this needs to evolve to IVars or equivalent
}
{-
data Expression b where
Binding :: Variable b -> Expression a -> Expression b
Comment :: Rope -> Expression ()
Declaration :: (a -> b) -> Expression (a -> b)
Application :: Expression (a -> b) -> Expression a -> Expression b
Attribute :: Role -> Expression a -> Expression a
-}
-- Does this need to upgrade to a MonadEvaluate mtl style class in order to
-- support different interpeters / backends? This seems so cumbersome
-- compared to the elegent tagless final method.
newtype Evaluate a = Evaluate (ReaderT Context IO a)
deriving (Functor, Applicative, Monad, MonadIO, MonadReader Context)
unEvaluate :: Evaluate a -> ReaderT Context IO a
unEvaluate (Evaluate r) = r
-- |
-- The heart of the evaluation loop. Translate from the abstract syntax tree
-- into a monadic sequence which results in a Result.
evaluateStep :: Step -> Evaluate Value
evaluateStep step = case step of
Known _ value -> do
return value
Depends _ name -> do
blockUntilValue name
Tuple _ steps -> do
values <- traverse evaluateStep steps
return (Parametriq values)
Asynchronous _ names substep -> do
promise <- assignNames names substep
undefined -- TODO put promise into environment
Invocation _ attr func substep -> do
functionApplication func substep -- TODO do something with role!
functionApplication :: Function -> Step -> Evaluate Value -- IO Promise ?
functionApplication = undefined
executeAction :: Function -> Step -> Evaluate Value -- IO Promise ?
executeAction = undefined
blockUntilValue :: Name -> Evaluate Value
blockUntilValue = undefined
-- |
-- Take a step and lauch it asynchronously, binding its result to a name.
-- Returns a promise of a value that can be in evaluated (block on) when
-- needed.
assignNames :: [Name] -> Step -> Evaluate Promise
assignNames = do
-- dunno
return (undefined) -- fixme not empty list