{----------------------------------------------------------------------------- reactive-banana ------------------------------------------------------------------------------} {-# LANGUAGE RecursiveDo, BangPatterns #-} module Reactive.Banana.Prim.Evaluation where import qualified Control.Exception as Strict (evaluate) import Data.Monoid import Data.List (foldl') import qualified Reactive.Banana.Prim.Dated as Dated import qualified Reactive.Banana.Prim.Dependencies as Deps import Reactive.Banana.Prim.Order import Reactive.Banana.Prim.Plumbing import Reactive.Banana.Prim.Types {----------------------------------------------------------------------------- Graph evaluation ------------------------------------------------------------------------------} -- | Evaluate all the pulses in the graph, -- Rebuild the graph as necessary and update the latch values. step :: Inputs -> Step step (pulse1, roots) state1 = {-# SCC step #-} mdo let graph1 = nGraph state1 latch1 = nLatchValues state1 time1 = nTime state1 -- evaluate pulses while recalculating some latch values ((_, latchUpdates, output), state2) <- runBuildIO state1 $ runEvalP pulse1 $ evaluatePulses graph1 roots let -- updated graph dependencies graph2 = nGraph state2 -- update latch values from accumulations latch2 = appEndo latchUpdates $ nLatchValues state2 -- calculate output actions, possibly recalculating more latch values (actions, latch3) = Dated.runDated output latch2 -- make sure that the latch values are in WHNF Strict.evaluate $ {-# SCC evaluate #-} latch3 return (actions, Network { nGraph = graph2 , nLatchValues = latch3 , nTime = Dated.next time1 }) type Result = (EvalL, [(Position, EvalO)]) type Q = Deps.DepsQueue -- | Update all pulses in the graph, starting from a given set of nodes evaluatePulses :: Graph -> [SomeNode] -> EvalP Result evaluatePulses Graph { grDeps = deps } roots = go mempty [] $ insertList roots Deps.emptyQ where order = Deps.dOrder deps go :: EvalL -> [(Position,EvalO)] -> Q SomeNode -> EvalP Result go el eo !q1 = {-# SCC go #-} case Deps.minView q1 of Nothing -> return (el, eo) Just (a, q2) -> case a of P p -> evaluateP p >>= \c -> case c of Deps.Children -> go el eo $ insertList (Deps.children deps a) q2 Deps.Done -> go el eo q2 L l -> evaluateL l >>= \x -> go (el `mappend` x) eo q2 O o -> evaluateO o >>= \x -> go el ((positionO o, x):eo) q2 insertList :: [SomeNode] -> Q SomeNode -> Q SomeNode insertList xs q = {-# SCC insertList #-} foldl' (\q node -> Deps.insert (level node order) node q) q xs