I'll have an attempt at addressing the questions, although I freely admit that I'm not as "into" Reactive as Conal is yet, so he may come and correct me in a minute.

On 17 Dec 2008, at 15:29, Henrik Nilsson wrote:

I have not used Reactive as such, but I did use "Classic FRP"
extensively, and as far as I know the setup is similar, even
if Reactive has a modern and more principled interface.

Based on my Classic FRP experience (which may be out of date, if so,
correct me), I'd say advantages of Yampa are:

 * More modular.

   Yampa's signal function type is explicitly parameterized on the
   input signal type. In Classic FRP and Reactive (as far as I know),
   the system input is implicitly connected to all signal functions
   (or behaviours) in the system.

   One consequence of this is that it there were issues with reusing
   Classical FRP for different kinds of systems inputs, and difficult
   to combine systems with  different kinds of input. This was what
   prompted a parameterization on the type of the system input in the
   first place, which eventually led to Arrowized FRP and Yampa.

   I don't know what the current story of Reactive is in this respect.
   But having parameterized input has been crucial for work on big,
   mixed-domain, applications. (For example, a robot simulator with an
   interactive editor for setting up "the world". The robots were
   FRP systems too, but their input is naturally of a different kind
   that the overall system input. It also turned out to be very useful
   to have an FRP preprocessor for the system input, which then was
   composed with the rest of the system using what effectively was
   arrow composition (>>>), but called something else at the time.)

I'm not sure how this was set up in a classic FRP system, so I'm unable to comment on how exactly it's changed. What I will say is that as far I understand what you're saying, Reactive has explicitly parameterized inputs. In your robot example I would expect something along the lines of

data RobotInputs = RI {lightSensor :: Behavior Colour; bumbSwitch :: Event ()} -- A couple of example robot sensors

robotBehavior :: RobotInputs -> Behavior Robot
robotBehavior sensors = a behovior that combines the light sensor and the bumb switch to stay in the light, but not keep driving into things.

data UIInputs = UI {mousePoint :: Behavior Point; mouseClick :: Event (); ...}

world :: UIInputs -> Behavior World
world = interpret mouse and produce a world with barriers, robots and lights in it

robotInputs :: World -> Behavior Robot -> RobotInputs
robotInputs = given a robot in a world, generate the robot's inputs

 * A clear separation between signals, signal functions, and ordinary
   functions and values, yet the ability to easily integrate all kinds
   of computations.

   Arguably a matter of taste, and in some ways more a consequence of
   the Arrow syntax than Arrows themselves. But in Classical FRP,
   one had to do either a lot of explicit lifting (in practice, we
   often ended up writing lifting wrappers for entire libraries), or
   try to exploit overloading for implicit lifting. The latter is
   quite limited though, partly due to how Haskell's type classes
   are organized and that language support for overloaded constants
   is limited to numerical constants.

   In any case, when we switched to arrows and arrow syntax, I found
   it liberating to not have to lift "everything" to signal functions
   first, but that I could program both with signals and signal
   functions on the one hand, and plain values and functions on the
   other, at the same time and fairly seamlessly. And personally,
   I also felt this made the programs conceptually clearer and easier
   to understand,

   My understanding is that Reactive is similar to Classical FRP in
   this respect.

I agree and disagree here (that'll be the matter of taste creeping in). I agree that in Reactive you often spend a lot of keystrokes lifting pure values into either an Event or a Behavior. Having said that I'd argue that Yampa requires us to do this too -- it merely enforces the style in which we do it (we must do it with arrows).

My personal opinion on this one is that I prefer the applicative interface to the arrow based one, because it feels more like just writing a functional program.

 * Classical FRP lacked a satisfying approach to handle dynamic
   collections of reactive entities as needed when programming
   typical video games for example. Yampa has a way. One can
   argue about how satisfying it is, but at least it fulfills
   basic requirements such that allowing logically removed entities to
   be truly removed (garbage collected).

   I don't know where Reactive stands here.

I reserve judgement at the moment because I haven't explicitly written a reactive program involving a collection of behaviors, having said that, I see no reason why removing a value from the list in a Behavior [a], it should not get garbage collected.

 * There was also an issue with Classical FRP having to do with the
   need to observe the output from one part of the system in
   another part of the system. This is quite different from
   parameterizing the second part of the the system on the first,
   as this approach loses sharing across switches. This led to the
   development for "running in" constructs, which effectively
   made it possible for behaviours to be both signals (i.e.
   signal functions already applied to the system input),
   and signal functions (not yet applied to the system input).

   Yet there was no distinction between these "running behaviours"
   (= signals) and normal behaviours (= signal functions) at the
   type level. The approach also led to semantic difficulties, and,
   when trying to resolve those, to a very complicated design
   involving complicated overloading and auxiliary classes.

   The arrows approach obviated the need for all of this, and
   I consider that and other distinct advantage.

   Again, I don't know where Reactive stands here, but it needs to
   have a good answer to this issue, or it is going to suffer from
   limited expressivity.

My understanding is that Conal went to great lengths to make sure that Behaviors get correctly cached, so that incremental values are only evaluated once, but I'm affraid I can't answer this more sensibly.

Many of the above advantages are matters of opinion (but so are the
advantages initially put forward for Reactive above). However,
the development of AFRP and Yampa was motivated by fundamental
expresssivity limitations of Classical FRP, in at least some ways
related to the very way the system was set up. To the extent Reactive
is similar in style to Classical FRP, I think Reactive also needs to
address those questions.

Yep, I very much agree that these are mostly matters of taste, I hope I did something to answer some of the questions, and sorry I didn't give a better example particularly in the case of the last question.

Your email triggered to think about a couple of the other significant differences between Yampa and Reactive * Reactive deals with continuous functions of time, not sampled ones. This allows for asynchronous sampling, for example the ability to sample a Behavior at 1/60th of a second rate for screen refreshes, while sampling the same behavior also at 1/10th second for logging, and 1/1000th for euler integration of un-integratable Behaviors. * Reactive is push based. The result of this is that we will not waste CPU cycles for example refreshing the screen when nothing has changed on the output.

There are however a number of problems that Yampa certainly did solve that Reactive does not (yet), for example, recursive integrals do not yet always work correctly in Reactive (although when working, they should be totally transparent). It is also much harder to make a space leak in a Yampa program than in a Reactive one, thanks to the protective nest of Signal Functions. I think this is really a general problem of Haskell programming though -- it's possible to create space leaks, be careful!

Thanks

Tom Davie

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to