[Haskell-cafe] Yampa vs. Reactive

Henrik Nilsson nhn at Cs.Nott.AC.UK
Thu Dec 18 13:06:46 EST 2008


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?

 > 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.

 > 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.

 > >   let
 > >     n :: Behavior Int
 > >    n = <behaviour that counts left mouse button clicks>
 > >   in
 > >     n `until` <some event> -=> n
 > >
 > > I'm not sure I got the syntax right. But the idea is that we
 > > output the number of left mouse button clicks, and then at some
 > > point, we switch to a behavior that again output the number of left
 > > mouse button clicks, notionally the "same" one "n".
 > >
 > > The question is, after the switch, do we observe a count that
 > > continues from where the old one left off, i.e. is there a
 > > single *shared* instance of "n" that is merely being *observed*
 > > from within the two "branches" of the switch, or is the counting
 > > behavior "n" restarted (from 0) after the switch?
 >
 > 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).

 > 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?

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.

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!

Best,

/Henrik

-- 
Henrik Nilsson
School of Computer Science
The University of Nottingham
nhn at cs.nott.ac.uk


This message has been checked for viruses but the contents of an attachment
may still contain software viruses, which could damage your computer system:
you are advised to perform your own checks. Email communications with the
University of Nottingham may be monitored as permitted by UK legislation.



More information about the Haskell-Cafe mailing list