reactive-banana-1.3.2.0: src/Reactive/Banana/Prim/Mid/IO.hs
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecursiveDo #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-----------------------------------------------------------------------------
reactive-banana
------------------------------------------------------------------------------}
module Reactive.Banana.Prim.Mid.IO where
import Control.Monad.IO.Class
( liftIO )
import qualified Data.Vault.Lazy as Lazy
import Reactive.Banana.Prim.Mid.Combinators (mapP)
import Reactive.Banana.Prim.Mid.Evaluation (step)
import Reactive.Banana.Prim.Mid.Plumbing
import Reactive.Banana.Prim.Mid.Types
import qualified Reactive.Banana.Prim.Low.Ref as Ref
debug :: String -> a -> a
debug _ = id
{-----------------------------------------------------------------------------
Primitives connecting to the outside world
------------------------------------------------------------------------------}
-- | Create a new pulse in the network and a function to trigger it.
--
-- Together with 'addHandler', this function can be used to operate with
-- pulses as with standard callback-based events.
newInput :: forall a. Build (Pulse a, a -> Step)
newInput = mdo
always <- alwaysP
_key <- liftIO Lazy.newKey
nodeP <- liftIO $ Ref.new $ P $ PulseD
{ _keyP = _key
, _seenP = agesAgo
, _evalP = readPulseP pulse -- get its own value
, _nameP = "newInput"
}
let pulse = Pulse{_key,_nodeP=nodeP}
-- Also add the alwaysP pulse to the inputs.
let run :: a -> Step
run a = step ([nodeP, _nodeP always], Lazy.insert _key (Just a) Lazy.empty)
pure (pulse, run)
-- | Register a handler to be executed whenever a pulse occurs.
--
-- The pulse may refer to future latch values.
addHandler :: Pulse (Future a) -> (a -> IO ()) -> Build ()
addHandler p1 f = do
p2 <- mapP (fmap f) p1
addOutput p2
-- | Read the value of a 'Latch' at a particular moment in time.
readLatch :: Latch a -> Build a
readLatch = readLatchB