I have the following test program:
{-# LANGUAGE RankNTypes #-}
module Main where
import Reactive.Banana
import Reactive.Banana.Frameworks
import Reactive.Banana.Switch
import Data.IORef
import Control.Monad
main = do
fShowRef <- newIORef (const (return ()))
fNumRef <- newIORef (const (return ()))
let
netDesc :: forall t. Frameworks t => Moment t ()
netDesc = do
(eNum, fNum) <- newEvent
(eShow, fShow) <- newEvent
liftIO (writeIORef fShowRef fShow)
liftIO (writeIORef fNumRef fNum)
let beh = stepper 0 eNum
behTrimmed <- trimB beh
reactimate (printInitial behTrimmed <$ eShow)
actuate =<< compile netDesc
fNum <- readIORef fNumRef
fNum 1
fShow <- readIORef fShowRef
fShow ()
printInitial :: AnyMoment Behavior Int -> IO ()
printInitial beh = do
let
netDesc :: forall t. Frameworks t => Moment t ()
netDesc = do
behNow <- now beh
initVal <- initial behNow
liftIO (print initVal)
-- compiling is enough, I just want to see the initial value
void (compile netDesc)
I expected this to print
1
but it prints
0
I am creating a network with two events. eNum
is an event of Int
s, eShow
one of ()
. Whenever eShow
is raised, printInitial
is executed.
printInitial
prints the initial value of the behavior trimB (stepper 0 eNum)
. I thought that trimB
followed by now
discards the history before the point at which the network description in which it is contained is compiled. This would mean that every time eShow
is raised, a new behavior appears starting with the value of beh
at that time. Apparently, that's not the case.
So,
- what is the purpose of
trimB
? - is it possible to transform
x :: Behavior t0 a
toy :: Behavior t1 a
such thatinitial y
is the value ofx
att1
?
Your intuition is (supposed to be) correct:
trimB
followed bynow
should return the current value of the Behavior.However, your code has a serious problem: It uses a
Behavior
created in one network (compile
) during the compilation of another network (secondcompile
). The result of this is undefined — even though the types seem to work out! I'm sorry about that.I have pondered about this for some time, and hoped that nobody would try this combination. In principle, it is possible to disallow this scenario via the type system, Unfortunately, this would mean a second phantom parameter, and I didn't want to increase the notational burden even further, so I left it at the "please don't do this" contract.
As for your question:
trimB
andtrimE
are only used for changing the starting time of a Behavior resp. an Event within one network to allow dynamic switching. Semantically, thetrimB
function even seems to be a no-op, but internally, it is necessary to trim it.