Questions
Question 1
I can't just do what i did above when trying to add int's together.
Well, that's actually the point. In reactive programming, you don't want to imperatively add two numbers together, instead you want to define the new number in terms of the other numbers. Therefore, c = a + b
, such c
is always equal to a + b
, even when a
or b
changes: c
is reactive in respect to a
and b
.
var a = new BehaviorSubject(3);
var b = new BehaviorSubject(1);
var c = Rx.Observable.combineLatest(a, b, function(vals) {
return vals[0] + vals[1];
});
Question 2
I was wondering how exactly one would implement the example given in the 2nd highest rated answer.
Simplest answer lists and higher-order functions in haskell.
Answer you don't want Functional-reactive programming goes against everything you've learned in imperative programming, and you're going to have to re-learn how to do things if you want to do pure functional reactive programming. If you don't, you're going to end up making all kinds of dependancy tracking libraries like KnockoutJS, when you could do the same thing in a couple of hundred lines with something like RxJS-Splash, if you used FRP to begin with. (note how Splash is based on Rx, which is reusable code, and Knockout is purely implementation specific code).
FRP has a concept of events and time, whereas dependency tracking only has concepts of values and changes. Functional-reactive code has been around just as long as imperative code. It's not "built on top of imperative code." (yes it still compiles to assembly... not the point), it's fundamentally different in concept.
Example
Using Microsoft's Reactive Extensions for JavaScript (RxJS)
Keep in mind, Rx is available in a lot of languages now, including native C++.
Direct Port of Example
var moves = $(document).onAsObservable('mousemove')
.map(function(e) {
return {
x: e.pageX,
y: e.pageY
};
});
var xs = moves.map(function(move) { return move.x; });
var ys = moves.map(function(move) { return move.y; });
var minXs = xs.map(function(x) { return x - 16; });
var minYs = ys.map(function(y) { return y - 16; });
var maxYs = xs.map(function(x) { return x + 16; });
var maxYs = ys.map(function(y) { return y + 16; });
var boundingRect = Rx.Observable.combineLatest(minXs, minYs, maxXs, maxYs)
.map(function(vals) {
var minX = vals[0];
var minY = vals[1];
var maxX = vals[2];
var maxY = vals[3];
return new Rectangle(minX, minY, maxX, maxY);
});
Simplified Port
Since the rectangle is defined only in terms of one dependent value (or event), then you can simplify this to the following:
var boundingRect = $(document).onAsObservable('mousemove')
.map(function(e) {
var x = e.pageX;
var y = e.pageY;
return new Rectangle(x - 16, y - 16, x + 16, y + 16);
});
Using It
At which point you can use it to compose other observable sequences (values which changes over time).
var area = boundingRect.map(function(rect) {
return rect.getSize();
});
Or subscribe to it directly.
boundingRect.subscribe(function (rect) {
// perform some action with the rect each time it changes.
console.log(rect);
});
But that's only when it changes!
What if we want the latest value as soon as we subscribe, rather than having to wait for the rectangle to change again? Well, that's where BehaviorSubject
s come in.
var rects = new Rx.BehaviorSubject(new Rectangle(-1, -1, 1, 1));
rects.subscribe(function(rect) {
// this would happen twice in this example.
// Once for the initial value (above), and once when it is changed later (below).
console.log(rect);
});
rects.onNext(new Rectangle(-1, -1, 1, 1));
But that's not the original observable, and it's not very functional...
Here's how to do the same thing with the original observable using some built in functionality to change on Observable to a act like a BehaviorSubject...
var rectsAndDefault = rects.startWith(new Rectangle()); // just give it an initial value
rectsAndDefault.subscribe(function(rect) {
console.log(rect); // happens once for the "startWith" rectangle, and then again for all subsequent changes
})
Again, FRP is different. It's good different, but it's a big undertaking to learn. You'll know you've started getting it when it starts blowing your mind.