The answer seems to be "it's sort of possible".
sample corresponds to valueB, but there is no direct equivalent to sync.
However, it can be re-implemented with the help of execute:
module Sync where
import Control.Monad.Trans
import Data.IORef
import Reactive.Banana
import Reactive.Banana.Frameworks
data Network = Network { eventNetwork :: EventNetwork
, run :: MomentIO () -> IO ()
}
newNet :: IO Network
newNet = do
-- Create a new Event to handle MomentIO actions to be executed
(ah, call) <- newAddHandler
network <- compile $ do
globalExecuteEV <- fromAddHandler ah
-- Set it up so it executes MomentIO actions passed to it
_ <- execute globalExecuteEV
return ()
actuate network
return $ Network { eventNetwork = network
, run = call -- IO Action to fire the event
}
-- To run a MomentIO action within the context of the network, pass it to the
-- event.
sync :: Network -> MomentIO a -> IO a
sync Network{run = call} f = do
-- To retrieve the result of the action we set up an IORef
ref <- newIORef (error "Network hasn't written result to ref")
-- (`call' passes the do-block to the event)
call $ do
res <- f
-- Put the result into the IORef
liftIO $ writeIORef ref res
-- and read it back once the event has finished firing
readIORef ref
-- Example
main :: IO ()
main = do
net <- newNet -- Create an empty network
(bhv1, set1) <- sync net $ newBehavior (0 :: Integer)
(bhv2, set2) <- sync net $ newBehavior (0 :: Integer)
set1 3
set2 7
let sumB = (liftA2 (+) bhv1 bhv2)
print =<< sync net (valueB sumB)
set1 5
print =<< sync net (valueB sumB)
return ()
Behavior
only makes sense in the context of aMoment
, i.e. at a particular moment in time, whichIO
does not provide. This is not just a theoretical issue, but is important for the internal consistency of the implementation, so I'm hesitating to add a function like this. Could you elaborate on the specific context in which you want to use this (dbus)? Chances are that it can be expressed in a different way. – Conformitysync
, because you could try to use it in another network, which will fail horribly. – Conformitysample
just worked there? Can I assume it was because it was breaking some laws...? Or was it a (safe) hack? Another question: could we simply generate an event that happens every, say, 0.01s,<@
that into the behavior, and get back roughly what Sodium offers? That would be less accurate but depending on needs, might work. (on another note: my gut feeling though is still to track what really is the underlyingEvent
that directly or indirectly causes the vaue of theBehavior
to change, and use that.) – Manardsample
that did (probably dependent-types based) analysis to see if there is indeed an underlyingEvent
from which theBehavior
is computed, and automatically<@
with thatEvent
? but cause a compile error if no suchEvent
exists? But then again, outside "influence" is always ultimately anEvent
, so I thinksample
could always just work and thus deptypes would not even be needed...? – ManardBehavior
can obviously also lazily read from an external resource (although, under the hood, absolutely everything is interrupt-based, so at least conceptually it's all event-based), so I guess deptypes or equiv. would still be needed. – ManardEvent
from aBehavior
under observation — becausevalueB
is nice but it does not stay within the pure world of events and behaviors, but a deeper solution could. Looking forward to a reply by @HeinrichApfelmus – Manard