{-# 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