11

Pardon me, I'm just starting to look into reactive-banana and FRP.

The author of reactive-banana made this example per my suggestion, in which he creates a counter which can be increased and decreased. He uses accumE function which accumulates events. I think I was able to somewhat grok the Event type, and was able to test quite a few things with it, but then I remembered that there was also Behavior. I looked into it, but it seems like the behavior is meant to be used in similar situations; to modify an existing variable, just like accumE does with events.

What does Behavior mean, and what are the use cases for it?

HaskellElephant
  • 9,819
  • 4
  • 38
  • 67
Masse
  • 4,334
  • 3
  • 30
  • 41

4 Answers4

10

I agree with Ankur rather than Chris: a text box is a value over time and so naturally wants to be a behavior rather than an event. The reasons Chris give for the less natural choice of event are implementation issues and so (if accurate) an unfortunate artifact of the reactive-banana implementation. I'd much rather see the implementation improved than the paradigm used unnaturally.

Besides the semantic fit, it's pragmatically very useful to choose Behavior over Event. You can then, for instance, use the Applicative operations (e.g., liftA2) to combine the time-varying text box value with other time-varying values (behaviors).

Conal
  • 18,517
  • 2
  • 37
  • 40
  • Note that the value of a text box is inherently a *discontinuous* function of time, which I suspect is the cause of both the implementation issues and the perception that `Behavior` is less natural. This differs from, say, the position of a moving image on the screen, which is very naturally continuous. Would the *derivative* of the text box be a `Behavior` or an `Event`? – C. A. McCann Jul 01 '11 at 20:55
  • 1
    Do you really mean dis/continuous function of time, or function of dis/continuous time? Behaviors are about functions of continuous time, not continuous functions of time. – Conal Jul 06 '11 at 17:44
  • Because it takes discrete values, and it's not meaningful to talk of changes in value occupying time spans. If the text box value over time is *tb(t)*, and goes from *tb(n) = "ab"* to *tb(n + 0.5) = "abc"*, the change is (++ "c") over the interval. If *tb(n + 0.25) = X*, the change from "ab" to X plus the change from X to "abc" should equal (++ "c"). There's no semantically meaningful way I can think of to divide (++ "c") in half, so the change must occur before or after X. Repeating the argument shows changes must have a duration of 0, making *tb(t)* a discontinuous function. – C. A. McCann Jul 06 '11 at 18:13
  • Oops, sorry, didn't see your edit to the comment. Yes, I meant a discontinuous function defined over continuous time, the "derivative" of which can only be sensibly interpreted as a function defined only for certain, discrete times. My impression is that's roughly what `Event` means but I could be wrong. The distinction I was trying to draw is that while any function defined over continuous time would be a `Behavior`, there's an intrinsic and meaningful difference between conceptually continuous vs. discontinuous functions. – C. A. McCann Jul 06 '11 at 18:16
  • Ah. So you're interested in continuous functions and more specifically *differentiable* functions. Which does not correspond to the original question of Behavior vs Event. Probably just a confusion around continuous time-functions vs continuous-time functions. – Conal Jul 06 '11 at 19:29
  • By the way, consider the example of a time-varying string defined to continuously hold a representation of the value of a continuously changing real number (e.g. time, distance, temperature). And now suppose that string is the content of a text box. – Conal Jul 06 '11 at 19:33
  • Yes, I've probably misunderstood the semantics of `Event` here to some extent, my apologies. I'm also starting to think that the perspective I'm coming from doesn't mesh with reactive-banana anyhow, so my remarks are probably irrelevant. Oh well. – C. A. McCann Jul 06 '11 at 19:47
6

Semantically, you have

Behavior a = Time -> a

That is, a Behavior a is a value of type a that varies over time. In general, you know nothing at all about when a Behavior a would change, so it turns out to be a rather poor choice for updating a text field on the click of a button. That said, it would be easy to get a behavior that expresses the current value of the number in the counter example. Just use stepper on the event stream, or alternatively, build it from scratch the same way, except by using accumB instead of accumE.

Typically, things you hook up to input and output will always be Events, so Behavior is used internally for intermediate results.

Suppose that in the given example, you want to add a new button that remembers the current value, like the memory function on simple calculators. You would start out by adding a memory button and a text field for the remembered value:

bmem    <- button f [text := "Remember"]
memory  <- staticText f []

You need to be able to ask for the current value at any time, so in your network, you'd add a behavior to represent it.

let currentVal = stepper 0 counter

Then you can hook up events, and use apply to read the value of the behavior every time the Remember button is pressed, and produce an Event with that sequence of values.

emem <- event0 bmem command
let memoryE = apply (const <$> currentVal) emem

And finally, hook up this new event to the output

sink memory [text :== ("", show <$> memoryE)]

If you wanted to use memory internally, then again you'd want a Behavior for its current value too... but since we only ever use it to connect it to an output, we only need an event for now.

Does that help?

Chris Smith
  • 2,615
  • 19
  • 18
5

Library author speaking. :-)

Apparently, Chris Smith can read minds because he accurately describes what I am thinking. :-)

But Conal and Arthur have a point, too. Conceptually, the counter is a value that varies in time, not a sequence of event occurrences. Thus, thinking of it as a Behavior would be more appropriate.

Unfortunately, behaviors do not come with any information about when they will change, the are "poll-only". Now, I could try to implement various clever schemes that will minimize the polling and thus allow effient updates of GUI elements. (Conal does something similar in the original paper.) But I have adopted a "no magic" philosophy: the library user shall be responsible for managing updates via events himself.

The solution I currently envision is to provide a third type besides Event and Behavior, namely Reactive (name subject to change) which embodies qualities of both: conceptually, it's a value that varies in time, but it also comes with an event that notifies of changes. One possible implementation would be

type Reactive a = (a,Event a)

changes :: Reactive a -> Event a
changes (_, e) = e

value :: Reactive a -> Behavior a
value   (x, e) = stepper x e

It is no surprise that this is precisely the type that sink expects. This will be included in a future version of the reactive-banana library.

EDIT: I have released reactive-banana version 0.4 which includes the new type, which is now called Discrete.

Community
  • 1
  • 1
Heinrich Apfelmus
  • 11,034
  • 1
  • 39
  • 67
  • I'm sorry to see the semantic model and interface getting more complex for purely operational/implementation reasons. – Conal Jul 06 '11 at 17:58
  • If you do stick with this new, implementation-driven type, I recommend against the name "Reactive", since the semantic inconsistency with my use in *[Push-pull functional reactive programming](http://conal.net/papers/push-pull-frp/)* would likely lead to confusion. – Conal Jul 06 '11 at 18:05
  • Basing UI updates directly on a value over time is arguably a conceptual mismatch anyway. Updates care about changes, not values. The motivation for making the distinction outlined in my comments on Conal's answer is that I've found many elements of a system have cleaner semantics when viewed as a sort of derivative. Actually applying the updates may further involve summing the derivative over the time since the last UI update, but this is a definite integral, and conceptually distinct from the original function. – C. A. McCann Jul 06 '11 at 18:43
  • I relate to *"update"* as purely an implementation issue, in the service of presentation of information that varies with continuous time. I would never use an implementation issue to guide or justify a semantic model or API. Rather, I always aim to keep the model & API as simple & precise as possible, and then figure out how to implement that simple model & API faithfully. In other words, I do my best to provide beautiful abstractions *in spite of* the clunky operational building blocks I have at hand (machine architectures, operating systems, low-level windowing libs, etc). – Conal Jul 06 '11 at 19:05
  • In other words, I see update not as a notion *intrinsic* to UIs or to other time-varying phenomena, but rather as a secondary notion arising from wondering how to implement presentation of UIs (etc) on a class of machines and applying a class of imperative programming habits. – Conal Jul 06 '11 at 19:10
  • @Conal: Agreed, and please note that I prefer viewing things in terms of changes rather than values for conceptual reasons first, because it lets the system be described directly in terms of its behaviors, without implicitly basing things off some absolute reference point. To be fair, I'm essentially arguing that introducing non-relative values for *anything* constitutes an implementation detail, which is rather extreme and probably incompatible with many existing notions of FRP. – C. A. McCann Jul 06 '11 at 19:42
  • I can understand appeal of a differential perspective, especially a continuous one, where it fits. I don't see a natural connection with the discreteness imposed by events. Maybe there are at least two (probably more) topics getting entangled here. – Conal Jul 06 '11 at 20:49
  • @Conal: Very likely more, yes. :] Unfortunately, the comment system on SO actively discourages this sort of extended discussion, so I'll resist the temptation to elaborate further. That said, this has led me to more thoroughly consider some slightly nebulous ideas and helped me clarify how I think about the concepts, so I must thank you for your patience in replying here. – C. A. McCann Jul 06 '11 at 21:37
4

Generally, Behavior is a value that changes over a period of time. It is a continuous value, where as events are discrete values. In case of Behavior a value is always present. For example: The text on a text box is a Behavior as the text can change over a period of time but there will be a current value, where as a keyboard stroke in a event as you cannot query a keyboard stroke for its "current" value.

Ankur
  • 33,367
  • 2
  • 46
  • 72
  • 1
    As I mentioned in my answer, behaviors are actually not a very good match for setting text fields in something like reactive-banana, since calls to the underlying graphics library functions to set the value need to happen at discrete times, so you actually need the event to let you know when the changes occur. – Chris Smith Jun 30 '11 at 13:16
  • I'm with Ankur here, as reflected in my answer. – Conal Jul 01 '11 at 00:30