| Safe Haskell | None |
|---|---|
| Language | Haskell98 |
Reactive.Banana.Prim
Synopsis
- type Step = EvalNetwork (IO ())
- data Network
- emptyNetwork :: Network
- type Build = ReaderWriterIOT BuildR BuildW IO
- liftIOLater :: IO () -> Build ()
- type BuildIO = Build
- liftBuild :: Build a -> BuildIO a
- buildLater :: Build () -> Build ()
- buildLaterReadNow :: Build a -> Build a
- compile :: BuildIO a -> Network -> IO (a, Network)
- module Control.Monad.IO.Class
- module Reactive.Banana.Prim.Cached
- interpret :: (Pulse a -> BuildIO (Pulse b)) -> [Maybe a] -> IO [Maybe b]
- mapAccumM :: Monad m => (a -> s -> m (b, s)) -> s -> [a] -> m [b]
- mapAccumM_ :: Monad m => (a -> s -> m (b, s)) -> s -> [a] -> m ()
- runSpaceProfile :: Show b => (Pulse a -> BuildIO (Pulse b)) -> [a] -> IO ()
- newInput :: forall a. Build (Pulse a, a -> Step)
- addHandler :: Pulse (Future a) -> (a -> IO ()) -> Build ()
- readLatch :: Latch a -> Build a
- type Pulse a = Ref (Pulse' a)
- neverP :: Build (Pulse a)
- alwaysP :: Build (Pulse ())
- mapP :: (a -> b) -> Pulse a -> Build (Pulse b)
- type Future = IO
- tagFuture :: Latch a -> Pulse b -> Build (Pulse (Future a))
- unsafeMapIOP :: forall a b. (a -> IO b) -> Pulse a -> Build (Pulse b)
- filterJustP :: Pulse (Maybe a) -> Build (Pulse a)
- unionWithP :: forall a. (a -> a -> a) -> Pulse a -> Pulse a -> Build (Pulse a)
- type Latch a = Ref (Latch' a)
- pureL :: a -> Latch a
- mapL :: (a -> b) -> Latch a -> Latch b
- applyL :: Latch (a -> b) -> Latch a -> Latch b
- accumL :: a -> Pulse (a -> a) -> Build (Latch a, Pulse a)
- applyP :: Latch (a -> b) -> Pulse a -> Build (Pulse b)
- switchL :: Latch a -> Pulse (Latch a) -> Build (Latch a)
- executeP :: forall a b. Pulse (b -> Build a) -> b -> Build (Pulse a)
- switchP :: Pulse (Pulse a) -> Build (Pulse a)
Synopsis
This is an internal module, useful if you want to implemented your own FRP library. If you just want to use FRP in your project, have a look at Reactive.Banana instead.
Evaluation
Build FRP networks
liftIOLater :: IO () -> Build () Source #
buildLater :: Build () -> Build () Source #
buildLaterReadNow :: Build a -> Build a Source #
Pretend to return a value right now, but do not actually calculate it until later.
NOTE: Accessing the value before it's written leads to an error.
FIXME: Is there a way to have the value calculate on demand?
module Control.Monad.IO.Class
Caching
module Reactive.Banana.Prim.Cached
Testing
interpret :: (Pulse a -> BuildIO (Pulse b)) -> [Maybe a] -> IO [Maybe b] Source #
Simple interpreter for pulse/latch networks.
Mainly useful for testing functionality
Note: The result is not computed lazily, for similar reasons
that the sequence function does not compute its result lazily.
mapAccumM_ :: Monad m => (a -> s -> m (b, s)) -> s -> [a] -> m () Source #
Strict mapAccum for a monad. Discards results.
runSpaceProfile :: Show b => (Pulse a -> BuildIO (Pulse b)) -> [a] -> IO () Source #
Execute an FRP network with a sequence of inputs. Make sure that outputs are evaluated, but don't display their values.
Mainly useful for testing whether there are space leaks.
IO
newInput :: forall a. Build (Pulse a, a -> Step) Source #
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.
addHandler :: Pulse (Future a) -> (a -> IO ()) -> Build () Source #
Register a handler to be executed whenever a pulse occurs.
The pulse may refer to future latch values.
Pulse
Latch
Dynamic event switching
Notes
The Build monad is an instance of MonadFix and supports value recursion.
However, it is built on top of the IO monad, so the recursion is
somewhat limited.
The main rule for value recursion in the IO monad is that the action
to be performed must be known in advance. For instance, the following snippet
will not work, because putStrLn cannot complete its action without
inspecting x, which is not defined until later.
mdo
putStrLn x
let x = "Hello recursion"On the other hand, whenever the sequence of IO actions can be known
before inspecting any later arguments, the recursion works.
For instance the snippet
mdo
p1 <- mapP p2
p2 <- neverP
return p1works because mapP does not inspect its argument. In other words,
a call p1 <- mapP undefined would perform the same sequence of IO actions.
(Internally, it essentially calls newIORef.)
With this issue in mind, almost all operations that build Latch
and Pulse values have been carefully implemented to not inspect
their arguments.
In conjunction with the Cached mechanism for observable sharing,
this allows us to build combinators that can be used recursively.
One notable exception is the readLatch function, which must
inspect its argument in order to be able to read its value.