Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the 'Signal' representation of Functional Reactive Programming correct?

I have been researching FRP and found a bunch of different implementations. One model I have seen is one I will refer to as the 'Signal' representation. This essential combines Events and Behaviours into one entity.

Firstly, a Signal is an object thats value is a Behaviour. Secondly, a Signal has an Event 'stream' that can be seen and operated on as a standard data structure (you can use 'each', 'map' and 'filter' etc on the Signal to define how Events are reacted to). For example I can do this (where 'time' is a Signal representation of time):

time.each { t => print(t) } // every time there is a 'tick' the current time is printed
a = time * 5 //where 'a' would be a dynamic value always up to date with time

Is this representation of FRP correct or are there any problems? I quite like the way this works and also how simple it is to describe personally but I'm not sure its right.

like image 615
seadowg Avatar asked Sep 16 '11 23:09

seadowg


People also ask

Is reactive programming same as functional programming?

Functional programming paradigm is built upon the idea that everything is a pure function. Reactive programming paradigm is built upon the idea that everything is a stream observer and observable philosophy.

Is reactive programming functional?

Functional reactive programming (FRP) is a paradigm that combines the reactivity from reactive programming with the declarative function composition from functional programming. It simplifies complex tasks, creates elegant user interfaces, and manages state smoothly.

Is RxJs functional programming?

While RxJs is a functional programming library, it is also a reactive programming library. Reactive programming allows us to deal with the asynchronous nature of JavaScript in a seamless and very elegant manner.

What is functional reactive programming Swift?

The idea of reactive programming is that instead of manually and imperatively reading the state or value of some entity, you listen, or subscribe, to changes of that entity and get notified whenever your state changes — in which case, you can react to the change and update your app accordingly.


1 Answers

Unfortunately, coalescing "event" and "behavior" into a single entity "signal" doesn't work so well.

Most signal-based FRP implementations that I know end up creating an additional "event"-like type along the lines of

type Event a = Signal (Maybe a)

So, the concept of events doesn't go away, and there is no real simplification. In fact, I would argue that the signal type is a semantic complification. Signals are only popular because they are easier to implement.

The main argument against signals is that they cannot represent continuous time behaviors, because they have to cater to the discrete events. In Conal Elliott's original vision, behaviors were simple continuous functions of time

type Behavior a = Time -> a
-- = function that takes the current time as parameter and returns
--   the corresponding value of type  a

In contrast, signals always are always discretized and usually associated with a fixed time step. (It is possible to implement both events and behaviors on top of a variable time step signal, but it's not a good abstraction by itself.) Compare this to an event stream

type Event a = [(Time,a)]
-- list of pairs of the form (current time, corresponding event value)

where the individual events don't necessarily occur in regularly spaced time intervals.

The argument for the distinction between behaviors and events is that their API is quite different. The main point is that they have different product types:

(Behavior a , Behavior b) = Behavior (a,b)
(Event a    , Event b   ) = Event (a :+: b)

In words: a pair of behaviors is the same as a behavior of pairs, but a pair of events is the same as an event from either component/channel. Another point is that there are two operations

(<*>) :: Behavior (a -> b) -> Behavior a -> Behavior b
apply :: Behavior (a -> b) -> Event a    -> Event b

that have almost the same type, but quite different semantics. (The first updates the result when the first argument changes, while the second doesn't.)

To summarize: signals can be used for implementing FRP and are valuable for experimenting with new implementation techniques, but behaviors and events are a better abstraction for people who just want to use FRP.

(Full Disclosure: I have implemented an FRP library called reactive-banana in Haskell.)

like image 83
Heinrich Apfelmus Avatar answered Oct 21 '22 11:10

Heinrich Apfelmus