[Haskell-cafe] Yampa vs. Reactive

Thomas Davie tom.davie at gmail.com
Thu Dec 18 14:52:44 EST 2008

Hi Henrik,

On 18 Dec 2008, at 19:06, Henrik Nilsson wrote:

> Hi Tom,
> > I don't think this is really true.  Behaviors and Events do not  
> reveal
> > in their type definitions any relation to any system that they may  
> or
> > may not exist in.
> OK. So how does e.g.
>   mousePoint :: Behavior Point
> get at the mouse input? unsafePerformIO?
> I.e. it is conceptually a global signal?

main = adapter doSomeStuff

-- Note here that different adapters provide different "UI"s.
adapter :: (Behavior UI -> Behavior  
SomethingFixedThatYouKnowHowToInterpret) -> IO ()
adapter f = set up the system behaviors, pass them into f, grab the  
outputs, and do the "something" to render.

doSomeStuff :: Behavior UI -> Behavior  

> > I'm not sure I understand you clearly.  If I wish to apply a  
> constant > function to a signal, can I not just use fmap?
> The question is why I would want to (conceptually). I'm just saying
> I find it good and useful to be able to easily mix static values
> and computations and signals and computations on signals.

Yep, I can see that, I think we need to agree to disagree on this  
front, I would prefer to use fmap, or <$>, while you prefer arrow  

> > You would certainly need to ask Conal on this point, but I have no
> > reason to suspect that b' = [1,2,3,4,5] `stepper` listE [(1,[])]  
> would > not deallocate the first list once it had taken its step.
> It's not the lists that concern me, nor getting rid of a collection
> of behaviors all at once. The problem is if we ant to run a collection
> of behaviors in parallel, all potentially accumulating internal
> state, how do we add/delete individual behaviors to/from that
> collection, without "disturbing" the others?
> For the sake of argument, say we have the following list of  
> behaviours:
>    [integral time, integral (2 * time), integral (3 * time)]
> We turn them into a single behavior with a list output in order to
> run them. After one second the output is thus
>    [1,2,3]
> Now, we want to delete the second behavior, but continue to
> run the other two, so that the output at time 2 is
>    [2,6]
> Simply mapping postprocessing that just drops the second element
> from the output isn't a satisfactory solution.

I'm not sure why mapping the function is not satisfactory -- It would  
create a new Behavior, who's internals contain only the two elements  
from the list -- that would expose to the garbage collector that the  
second element has no reference from this behavior any more, and thus  
the whole behavior could be collected.

> > Yes, we really do get a shared n -- without doing that we certainly
> > would see a large space/time leak.
> Interesting, although I don't see why not sharing would imply
> a space/time leak: if the behavior is simply restarted, there
> is no catchup computation to do, nor any old input to hang onto,
> so there is neither a time nor a space-leak?
> Anyway, let's explore this example a bit further.
> Suppose "lbp" is the signal of left button presses, and that
> we can count them by
>   "count lbp"
> Then the question is if
>    let
>       n :: Behavior Int
>       n = count lbp
>    in
>       n `until` <some event> -=> n
> means the same as
>    (count lbp) `until` <some event> -=> (count lbp)
> If no, then Reactive is not referentially transparent, as we  
> manifestly
> cannot reason equationally.
> If yes, the question is how to express a counting that starts over
> after the switch (which sometimes is what is needed).

That's a yes.  My first answer to how to implement the resetting  
counter would be someting along the lines of this, but I'm not certain  
it's dead right:

e = (1+) <$ mouseClick
e' = (const 0) <$ <some event>
b = accumB 0 (e `mappend` e')

i.e. b is the behavior got by adding 1 every time the mouse click  
event occurs, but resetting to 0 whenever <some event> occurs.

> > Yep, such Behaviors are seperated in Reactive only by the method you
> > create them with.  I may use the `stepper` function to create a
> > behavior that increases in steps based on an event occurring, or I  
> may > use fmap over time to create a continuously varying Behavior.
> But the question was not about events vs continuous signals. The  
> question is, what is a behavior conceptually, and when is it started?
> E.g. in the example above, at what point do the various instances of
> "count lbp" start counting? Or are the various instances of "count  
> lbp"
> actually only one?

They are indeed, only 1.

> Or if you prefer, are beahviours really signals, that conceptually
> start running all at once at a common time 0 when the system starts?
> The answers regarding input behaviors like mousePosition, that
> "n is shared", and the need to do catchup computations all seem
> to indicate this. But if so, that leaves open an important
> question on expressivity, examplified by how to start counting from
> the time of a switch above, and makes if virtually impossible
> to avoid time and space leaks in general, at least in an embedded
> setting. After all, something like "count lbp" can be compiled into
> a function that potentially may be invoked at some point. And as
> long as this possibility exists, the system needs to hang on to
> the entire history of mouse clicks so that they can be coounted
> at some future point if necessary.

Yes, this certainly is an ongoing problem.  Currently there are  
certain situations in which the mouse click history is disposed of  
when we can show no one wants them any more, but this is not ideal.   
One possible solution is to make sure that all events and behaviors  
are updated continuously, but that may take a little more time than  
your solution.

> These are all questions that go back to classical FRP, which we
> didn't find any good answers to back then, and which also were
> part of the motivation for moving to AFRP/Yampa.
> If Reactive has come up with better answers, that would be very
> exciting indeed!

I'm not certain that the answers are better yet.  They feel more  
comfortable to me from a functional programming point of view, but it  
may yet turn out that space time leaks really are impossible to  
suppress.  My inclination at the moment is to believe that they are  


Tom Davie

More information about the Haskell-Cafe mailing list