Implementing reactive programming/functions in c#
I was recently reading up about game engine design and eventually ended up stumbling upon this: What is (functional) reactive programming?
I was wondering how exactly one would implement the example given in the 2nd highest rated answer. In C++ it'd be easy enough passing a pointer to the value that stores the mouse coordinates, and just returning the value of that instead of the int. Well, we can't really do that in C# so theres our first problem. do we need to call some 'update' function to keep all the values up to date?
secondly how would the syntax be handled? assigning values is straight forward. But doing things like 'get the mouses position and mins 14 from it every time i ask for it' is slightly more..complicated..
and lastly, I was wondering how you would make any object in C# return a value when you reference it directly. For example
int test = 1;
test would return 1. So i can do things like 1 + test which would = 2
but if i had an instance of
public class ReactiveInt {
int myValue
}
I can't just do what i did above when trying to add int's together.
Sorry for such a broad question I guess. If a simple example can be given that demonstrates functionality similar to what was discussed in that answer, i think all my questions would be answered..
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.
看看微软反应扩展(Rx)
使用Lambdas和Actions作为事件处理程序,您可以在没有指针的情况下离开。
int Offset = 16;
int Size = Offset * 2;
Action<MouseEventArgs> MouseEventArgsHandler = (args) => DrawRectangle(args.x - Offset, args.y - Offset, Size, Size);
链接地址: http://www.djcxy.com/p/47726.html
上一篇: 功能反应式编程(FRP)可以用monads来表示吗?
下一篇: 在c#中实现反应式编程/函数