7

私は最近、ゲーム エンジンの設計について読んでいて、最終的にこれに出くわしました: (関数型) リアクティブ プログラミングとは何ですか?

2 番目に高い評価の回答に示されている例を正確にどのように実装するのか疑問に思っていました。C++ では、マウス座標を格納する値へのポインターを渡し、int の代わりにその値を返すだけで十分簡単です。C# では実際にはできないので、最初の問題があります。すべての値を最新の状態に保つために、「更新」関数を呼び出す必要がありますか?

第二に、構文はどのように処理されますか? 値の割り当ては簡単です。しかし、「マウスの位置を取得し、要求するたびにそこから 14 分を取得する」などの作業は、少し複雑です..

最後に、C# の任意のオブジェクトを直接参照したときに値を返すようにする方法を考えていました。例えば

int test = 1;

test は 1 を返します。したがって、1 + test = 2 のようなことを行うことができます

しかし、もし私がのインスタンスを持っていたら

public class ReactiveInt {
     int myValue
}

intを一緒に追加しようとしたときに、上記のことを行うことはできません。

私が推測するような幅広い質問で申し訳ありません。その回答で説明されているものと同様の機能を示す簡単な例を示すことができれば、私のすべての質問に回答できると思います..

4

3 に答える 3

9

質問

質問1

intを一緒に追加しようとしたときに、上記のことを行うことはできません。

さて、それが実際のポイントです。リアクティブ プログラミングでは、2 つの数値を強制的に加算するのではなく、他の数値に関して新しい数値を定義する必要があります。したがって、c = a + b、そのようなcものは、またはが変更された場合でも、常にと等しくなります。 はおよびに関してリアクティブです。a + babcab

var a = new BehaviorSubject(3);
var b = new BehaviorSubject(1);
var c = Rx.Observable.combineLatest(a, b, function(vals) {
    return vals[0] + vals[1];
});

質問2

2 番目に高い評価の回答に示されている例を正確にどのように実装するのか疑問に思っていました。

Haskell の最も単純な回答リストと高階関数。

望まない回答関数型リアクティブ プログラミングは、命令型プログラミングで学んだことすべてに反するものであり、純粋な関数型リアクティブ プログラミングを実行したい場合は、その方法を再学習する必要があります。そうしないと、KnockoutJSのようなあらゆる種類の依存関係追跡ライブラリを作成することになります。最初に FRP を使用した場合、RxJS-Splashのようなものを使用して数百行で同じことを実行できます。. (Splash は再利用可能なコードである Rx に基づいており、Knockout は純粋に実装固有のコードであることに注意してください)。

FRP にはイベント時間の概念がありますが、依存関係追跡には変更の概念しかありません。機能的リアクティブ コードは、命令型コードと同じくらい長く使用されてきました。「命令型コードの上に構築された」ものではありません。(はい、それでもアセンブリにコンパイルされます...要点ではありません)、根本的に概念が異なります。

Microsoft の Reactive Extensions for JavaScript ( RxJS )の使用

Rx は現在、ネイティブC++を含む多くの言語で利用できることに注意してください。

例の直接ポート

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);
    });

簡略化されたポート

四角形は 1 つの依存値 (またはイベント) に関してのみ定義されるため、これを次のように簡略化できます。

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);
        });

それを使用する

その時点で、それを使用して他の観察可能なシーケンス (時間の経過とともに変化する値) を構成できます。

var area = boundingRect.map(function(rect) {
    return rect.getSize();
    });

または、直接購読してください。

boundingRect.subscribe(function (rect) {
    // perform some action with the rect each time it changes.
    console.log(rect);
    });

しかし、それはそれが変わるときだけです!

四角形が再び変化するのを待つのではなく、サブスクライブするとすぐに最新の値が必要な場合はどうすればよいでしょうか? さて、そこにBehaviorSubjects の出番です。

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));

しかし、それは元のオブザーバブルではなく、あまり機能的ではありません...

Observable を BehaviorSubject のような動作に変更する組み込み機能を使用して、元の Observable で同じことを行う方法を次に示します...

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
    })

やはりFRPは違います。違いはありますが、学ぶのは大変な作業です。それがあなたの心を吹き飛ばし始めたとき、あなたはそれを手に入れ始めたことを知るでしょう.

于 2013-03-12T19:44:19.117 に答える
1

Microsofts Reactive Extensions(Rx)をご覧ください

于 2012-04-20T13:09:46.120 に答える
0

Lambda と Action をイベント ハンドラーとして使用すると、ポインターがなくても問題を解決できます。

int Offset = 16;
int Size = Offset * 2;
Action<MouseEventArgs> MouseEventArgsHandler = (args) => DrawRectangle(args.x - Offset, args.y - Offset, Size, Size);
于 2012-02-09T21:22:00.893 に答える