The term “Functional-Reactive Programming” as a concept of computation is thrown around a lot today, and a bit like with Object-Oriented Programming, every person with an implementation of it seems to have their own definition.
Wikipedia: Functional reactive programming - Wikipedia
Basically, the idea is that everything in a software system (an application inside a web browser, usually, but if it’s a valid model of computation then theoretically it could be an entire application, OS, or network of computers) is a “pure function from input to output”. Pure functional languages usually struggle with I/O, because it involves change. The various approaches loosely described as “FRP” try to remove this element of change by pushing the change itself into a “framework”, while the components which handle this change remain “pure”.
It’s easy to glimpse the loose spirit of FRP by looking at a graphical window. There’s a bunch of components. Events come in (mouse clicks, keyboard presses, updates from the data source). Events go out (screen rewrites, changes of state of the components, changes to the data source). Naively, you’d think “this window is basically just a big function from a bunch of input events to a bunch of output events; why can’t I just write it as a function? A big pipe of data go in, data come out? Wouldn’t that be simpler than all this object stuff of setup and teardown, callbacks and promises, invocation ceremonies, component registries, mockups and tests and such?”
An even more naive, blurry, look at a window would make you think further “well this window is literally just a view of some data. A view is a function. Why can’t this window just be… a function call?”
Someone coming from the command-line world, especially Unix (or Powershell on Windows) might also think “All my text commands are pipes. Why isn’t my window a pipe?” And especially if they’ve used Tcl/Tk, they might ask “there’s a scripting language where windows literally are pipes, why is the whole world not like this?”
And presumably some of this thinking seeped into the huge Internet companies writing Web frontends, and became things like React, Reduct, Vue etc.
I’ve been watching the FRP scene from a distance for the last 20 years or so, and remain confused about how exactly the core paradigm is supposed to work. My feeling is that while the edges can be as complicated as you like, the core mechanism of “how computation happens” ought to be fairly simple and graspable. In Lisp, it’s “lists are rewritten into other lists”. In Forth, it’s “words put stuff on the stack”. In Smalltalk, it’s “objects send method selectors and arguments to objects and get replies”. In Fortran, Algol and all the little Algol children, it’s “I do this then I do that, then I go somewhere else and do what it says there”. 28 years after it was first introduced, FRP remains … not quite that clear. Something updates, or changes, or doesn’t change, or gets “reduced” or doesn’t, but what, and how?
One idea that was buzzing in my head around 20 years ago - under the influence of Joy and Factor at the time, and the revival of Forth - was this:
“FRP systems are really event-based programming. A program then looks pretty much like a pure function of a stream of input events, to a stream of output events. A graph of components, yes, but essentially a tree starting from the machine input. Each component in that graph/tree then could be expressed as a function which takes an input event, and replaces it with (zero, one or many) output events, and also an updated function to catch the next input event in the stream”.
I felt like this concept ought to be pretty simple and easy to grasp. Maybe too simple - it probably handwaves away all of the important detail. But I wanted to see it implemented.
I never did end up implementing it. Maybe it’s time to try.
20 years ago, I imagined the language and the evaluator as being a prefix-concatenative language, which are super rare, and haven’t been worked on in the years since. It seemed important at the time as a way of capturing the intuition that a software system might be able to represented just as an event stream with functions inside it, with functions plus arguments rewriting themselves to “output plus next version of function”. But a postfix language would probably have a simpler evaluator and might still be able to capture some of the essence of the idea.
Essentially, functions (or Joy-like combinators, or Forth-like words) would be coroutines: they could produce one value, then yield control to the next function up the pipe, then if reactivated, would recurse on themselves (updating some state, just like a “fold” or “reduce” function). I assume that this is essentially how modern web FRP frameworks like React work, since they use the term “reduce”. But React is a library over the whole object-based complexity of Javascript, the DOM and the browser. This would be something much simpler.
I feel like this must have been explored, and yet I don’t see where it has been explored.
I now have a vague sketch in my head of a modified two-stack postfix machine that feels like it ought to be able to naturally do coroutines over infinite streams of events. It would use a layered stack and a “yield” opcode so that calling between coroutines could be fairly efficient and also safe. I hope. I’ll try to build it to demonstrate what I mean. Whether this approach could actually help in reducing event-processing complexity, I’m not sure.
Edit: It turns out that the Wikipedia article on “Reactive Programming” is much more useful than the article on “Functional Reactive Programming”. I guess FRP lost its F in the last few years?