I think what you're describing results from a worst-case combination of three factors:<br><br>1. Infinitesimal delay semantics of switch<br>2. Euler integration<br>3. Exact synchronization of numerical integration time samples with display samples<br>
<br> Of these three factors, I see the first one as benign and semantically ideal. The imposed delay is the theoretical
minimum (infinitesimal) while still allowing meaningful specification
of self-reactive and mutually-reactive systems. And it's consistent
with differentially specified continuous behavior. On the other hand,
the second and third factors are implementation artifacts rather than
desirable semantics. Moreover, they're artifacts that cause the
implementation to stray from the semantic ideal.<br>
<br>My inclination is to embrace 1 and somehow fix 2 & 3. I'm guessing 3 is easy and 2 is hard.<br><br>For
3, I know of no benefit to having integration sample times correspond
to display times, or even to match the frequency. I implemented it
that way just for simplicity, and now I see it was a terrible idea. My
intention is to use a variable-step-size method that adapts to both the
nature of the behavior being integrated and to the available compute
cycles.<br>
<br>As for 2, I've used much better integration methods in the past.
What's tricky here is getting an integration method that works for
self- or mutully-recursive integration (i.e. ODE systems) *without* the
ability to see the cycles. Euler is easy but is terribly inaccurate or
inefficient&instable.<br>
<br> - Conal<br><br><div class="gmail_quote">2009/7/7 Patai Gergely <span dir="ltr"><<a href="mailto:patai_gergely@fastmail.fm">patai_gergely@fastmail.fm</a>></span><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Hello all,<br>
<br>
I opened a thread some time ago where I asked whether it's enough to<br>
have only immediate switching. But it dawned on me that Reactive<br>
switches are actually all delayed, since even though the delay is<br>
infinitesimal in principle, we still have to wait for the next point of<br>
observation until we can see its effect. This is a huge problem in<br>
practice, because this way every stateful signal imposes a delay equal<br>
to the length of the period between observations. Here's a simple test<br>
case for illustration:<br>
<br>
> import Control.Applicative<br>
> import FRP.Reactive<br>
><br>
> tick :: Event ()<br>
> tick = atTimes [0..]<br>
><br>
> behs :: [Behavior Double]<br>
> behs = pure 1 : map (integral tick) behs<br>
><br>
> eventList :: Event a -> [a]<br>
> eventList e = x : eventList e'<br>
> where (x,e') = firstRestE e<br>
><br>
> testBeh :: Behavior a -> [a]<br>
> testBeh b = take 10 $ eventList (snapshot_ b tick)<br>
><br>
> test :: IO ()<br>
> test = mapM_ (print . testBeh) (take 5 behs)<br>
<br>
Running test prints the following:<br>
<br>
[1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0]<br>
[0.0,0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]<br>
[0.0,0.0,0.0,1.0,3.0,6.0,10.0,15.0,21.0,28.0]<br>
[0.0,0.0,0.0,0.0,1.0,4.0,10.0,20.0,35.0,56.0]<br>
[0.0,0.0,0.0,0.0,0.0,1.0,5.0,15.0,35.0,70.0]<br>
<br>
I ran into the very same problem when working on the first version of<br>
Elerea. Transfer functions in version 0.1.0 behave exactly the same way,<br>
and I switched to immediate transfer functions from 0.2.0. The<br>
difference is obvious if you look at the breakout example in action: in<br>
0.1.0, the ball takes long to react to collisions, since the dependency<br>
cycle consists of three items (bricks, velocity, position), so any<br>
change takes just as many frames to propagate. From 0.2.0 onwards,<br>
collisions are much more accurate without any change in the example<br>
code.<br>
<br>
Sure, it is possible to work around the delay by combining the switching<br>
value with the one that caused its switch, but this adds a lot of<br>
complexity to the code on the user end. You can make life easier by<br>
introducing immediate versions as helper functions, but then you just<br>
reintroduced this distinction. Of course this is not surprising, since<br>
neither delayed nor immediate switching is sufficient on its own. But<br>
this means that Reactive should support both out of the box and not<br>
encourage ad hoc workarounds that are likely to break in unexpected<br>
ways. Also, immediate switching seems the more sensible default, because<br>
it's more straightforward to derive the delayed version from it than the<br>
other way around, and it is what we need most of the time.<br>
<br>
Are there any plans to address this problem? Or a completely new angle<br>
to look at it from?<br>
<br>
Gergely<br>
<font color="#888888"><br>
--<br>
<a href="http://www.fastmail.fm" target="_blank">http://www.fastmail.fm</a> - Faster than the air-speed velocity of an<br>
unladen european swallow<br>
<br>
_______________________________________________<br>
Reactive mailing list<br>
<a href="mailto:Reactive@haskell.org">Reactive@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/reactive" target="_blank">http://www.haskell.org/mailman/listinfo/reactive</a><br>
</font></blockquote></div><br>