packages feed

reactive-banana-0.6.0.0: src/Reactive/Banana/Internal/CompileModel.hs

{-----------------------------------------------------------------------------
    reactive-banana
------------------------------------------------------------------------------}
{-# LANGUAGE Rank2Types, ScopedTypeVariables #-}

module Reactive.Banana.Internal.CompileModel (
    -- * Synopsis
    -- Compile model implementation to automaton.
    
    InputToEvent(..), Compile, compileWithGlobalInput,
    ) where

import Control.Applicative
import Control.Exception (evaluate)
import Control.Monad
import Control.Monad.Trans.Reader
import Data.IORef
import Data.Maybe
import System.IO.Unsafe

import Reactive.Banana.Internal.InputOutput
import Reactive.Banana.Model

{-----------------------------------------------------------------------------
    Compile model to an automaton
------------------------------------------------------------------------------}
data InputToEvent = InputToEvent (forall a. InputChannel a -> Event a)
type Compile a b  = (InputToEvent -> IO (Event a,b)) -> IO (Automaton a,b)

compileWithGlobalInput :: Compile a b
compileWithGlobalInput f = do
    -- reference that holds input values
    (ref    :: IORef [InputValue]) <- newIORef undefined
    -- An infinite list of all future input values. Very unsafe!
    (inputs :: Event [InputValue]) <- unsafeSequence (Just <$> readIORef ref)
    
    let
        inputToEvent = InputToEvent $
            \i -> filterJust $ mapE (fromInputValues i) inputs
    
        filterJust = map fromJust . filter isJust
        
        fromInputValues :: InputChannel a -> [InputValue] -> Maybe a
        fromInputValues i xs = listToMaybe [y | x <- xs, Just y <- [fromValue i x]]
            

        -- step of the automaton
        step values outputs = do
            writeIORef ref values           -- write new input value
            (o:outputs) <- evaluate outputs -- make sure that output is in WHNF
            return (o, outputs)             -- return result
    
    (outputs, b) <- f inputToEvent
    return $ (fromStateful step outputs, b)


unsafeSequence :: IO a -> IO [a]
unsafeSequence m = unsafeInterleaveIO $ do
    x  <- m
    xs <- unsafeSequence m
    return (x:xs)