23

Classic FRP の最近の実装では、たとえばリアクティブ バナナには、ステップ関数であるイベント ストリームとシグナルがあります (リアクティブ バナナはそれらを動作と呼びますが、それでもステップ関数です)。Elm はシグナルのみを使用し、シグナルとイベント ストリームを区別していないことに気付きました。また、reactive-banana では、イベント ストリームからシグナルへの移行が可能です (編集済み: 良い習慣とは見なされていませんが、reactate を使用して動作に作用することは一種の可能性があります)。これは、理論的にはすべてのイベント ストリームを適用できることを意味します。最初にシグナルをイベントストリームに変換し、適用してから再度変換することにより、シグナル/動作のコンビネーター。したがって、一般に、1 つの抽象化だけを使用して学習する方が簡単であることを考えると、シグナルとイベント ストリームを分離する利点は何ですか? シグナルのみを使用し、すべてのイベント ストリーム コンビネータをシグナルで動作するように変換することで何かが失われますか?

編集:議論は非常に興味深いものでした. 私自身の議論から得た主な結論は、動作/イベント ソースは、相互に再帰的な定義 (フィードバック) と、出力が 2 つの入力 (動作とイベント ソース) に依存するものの両方に必要であるが、1 つの場合にのみアクションを引き起こすということです。それらの変更 (<@>)。

4

4 に答える 4

16

私にとって非常に重要な何か、つまり行動の本質、つまり継続的な時間にわたる (おそらく継続的な) 変化が失われています。正確でシンプルで便利なセマンティクス (特定の実装や実行とは無関係) も失われることがよくあります。「関数型リアクティブ プログラミング言語の仕様」に対する私の回答を確認し、そこにあるリンクをたどってください。

時間的にも空間的にも、時期尚早の離散化は構成可能性を妨げ、セマンティクスを複雑にします。ベクトル グラフィックス (およびPanのような他の空間的に連続したモデル) を検討してください。Why Functional Programming Mattersで説明されているように、データ構造の時期尚早な有限化と同様です。

于 2014-04-14T01:58:15.997 に答える
4

elm スタイルのシグナルに対してシグナル/動作の抽象化を使用する利点はないと思います。ご指摘のとおり、シグナル/動作 API の上にシグナルのみの API を作成することは可能です (まったく使用できる状態ではありませんが、https://github.com/JohnLato/impulse/blob/dyn2/src/を参照してください)。例としてReactive/Impulse/Syntax2.hsを参照)。elm スタイルの API の上にシグナル/動作 API を記述することも可能だと確信しています。これにより、2 つの API は機能的に同等になります。

WRT の効率性。シグナルのみの API を使用する場合、システムには、値が更新されたシグナルのみが再計算を引き起こすメカニズムが必要です (たとえば、マウスを動かさない場合、FRP ネットワークはポインター座標を再計算せず、再描画しません)。スクリーン)。これが行われていれば、シグナルとストリームのアプローチと比較して効率が低下することはないと思います。Elmがこのように機能すると確信しています。

ここでは、継続的な動作の問題が違いを生むとは思いません (またはまったく違います)。振る舞いが時間の経過とともに連続的であると人々が言うことは、それらが常に定義されているということです (つまり、それらは連続的なドメイン上の機能です)。動作自体は連続関数ではありません。しかし、実際にはいつでも動作をサンプリングする方法はありません。それらはイベントに対応する時間にしかサンプリングできないため、この定義の全機能を使用することはできません!

意味的には、次の定義から始めます。

Event    == for some t ∈ T: [(t,a)]
Behavior == ∀ t ∈ T: t -> b

動作はイベントが定義されているときにのみサンプリングできるため、イベントが定義されているすべての時間のセットでTXある新しいドメインを作成できます。これで、Behavior 定義を次のように緩めることができます。TXt

Behavior == ∀ t ∈ TX: t -> b

電力を失うことはありません (つまり、これは frp システムの範囲内での元の定義と同等です)。これで、すべての時間を列挙して、TXこれを次のように変換できます。

Behavior == ∀ t ∈ TX: [(t,b)]

Eventこれは、ドメインと定量化を除いて元の定義と同じです。の定義域EventTX( の定義によりTX) に変更し、 の量化をBehavior(forall から for some に) 変更すると、次のようになります。

Event    == for some t ∈ TX: [(t,a)]
Behavior == for some t ∈ TX: [(t,b)]

EventとnowBehaviorは意味的に同一であるため、明らかに FRP システムで同じ構造を使用して表すことができます。このステップで少し情報が失われます。を区別しないとEvent、 a が毎回定義されているBehaviorことがわかりませんが、実際には、これはあまり重要ではないと思います。elm が IIRC で行うことは、s とs の両方が常に値を持つことを要求し、変更されていない場合は前の値を使用することです(つまり、の数量化を変更する代わりに、の数量化を変更します)。BehaviortEventBehaviorEventEventforallBehavior)。これは、すべてを信号として扱うことができ、すべてがうまく機能することを意味します。信号ドメインがシステムが実際に使用する時間のサブセットになるように実装されているだけです。

このアイデアは、おそらく POPL '14 からの Java での FRP の実装に関する論文 (今は見つけられません。他の誰かがリンクを持っていますか?) で提示されたと思います。記憶に基づいて作業しているため、私の概要は元の証明ほど厳密ではありません。

Behaviorたとえば、より定義されたものを作成することを妨げるものは何もありませんpure someFunction。これは、FRP システム内ではその余分な定義性を利用できないことを意味するだけなので、より制限された実装によって何も失われることはありません。

時間などの概念的な信号に関しては、典型的なプログラミング言語を使用して実際の連続時間信号を実装することは不可能であることに注意してください。実装は必然的に個別になるため、それをイベント ストリームに変換するのは簡単です。

要するに、信号だけで損をすることはないと思います。

于 2014-04-10T21:56:32.480 に答える