(関数型) リアクティブ プログラミングとは何ですか?
-
06-07-2019 - |
質問
ウィキペディアの記事を読みました リアクティブプログラミング. 。に関する小さな記事も読みました 関数型リアクティブプログラミング. 。説明はかなり抽象的です。
- 関数型リアクティブ プログラミング (FRP) とは実際には何を意味しますか?
- リアクティブ プログラミング (非リアクティブ プログラミングとは対照的に) は何で構成されていますか?
私のバックグラウンドは命令型/OO 言語であるため、このパラダイムに関連する説明があれば幸いです。
解決
FRPの感触を味わいたいなら、古いものから始めるとよいでしょう。 フランのチュートリアル 1998 年から、アニメーションのイラストが描かれています。論文の場合は、以下から始めます 機能的なリアクティブアニメーション そして、私のホームページの出版物リンクと、 FRP のリンク ハスケルウィキ.
個人的にはFRPとは何かを考えるのが好きです 手段 それがどのように実装されるかを説明する前に。(仕様のないコードは、質問のない回答であり、したがって「間違っていない」という答えです。)したがって、トーマスKが別の回答(グラフ、ノード、エッジ、発射、実行、実行するように、表現/実装の用語でFRPについて説明しません。等)。可能な実装スタイルは数多くありますが、FRP がどのようなものであるかを示す実装はありません。 は.
私は、FRP が「『時間の経過に伴う』値を表すデータ型」に関するものであるという Laurence G の単純な説明に共鳴します。従来の命令型プログラミングは、これらの動的な値を状態と突然変異を通じて間接的にのみ取得します。完全な歴史 (過去、現在、未来) には、第一級の表現はありません。しかも、ただ、 個別に進化する 命令型パラダイムは時間的に離散的であるため、値を (間接的に) キャプチャできます。対照的に、FRP はこれらの進化する価値を捉えます 直接 そして何の困難もありません 継続的に 進化する価値観。
FRP は、命令型同時実行性を悩ませる理論的かつ実用的なネズミの巣に衝突することなく同時実行できるという点でも珍しいです。意味的には、FRP の同時実行性は次のとおりです。 きめの細かい, 決定的な, 、 そして 継続的な。(私は実装ではなく意味について話しています。実装は、同時性または並列性を伴う場合としない場合があります。)セマンティックな決定性は、厳密で非公式な推論にとって非常に重要です。同時実行により命令型プログラミングは (非決定性インターリーブにより) 非常に複雑になりますが、FRP では簡単です。
では、FRPとは何でしょうか?あなた自身がそれを発明したかもしれません。次のアイデアから始めてください。
動的/進化する値 (つまり、「時間の経過とともに」値) は、それ自体が第一級の値です。それらを定義して組み合わせたり、関数に渡したり関数から渡したりすることができます。私はこれらのことを「行動」と呼びました。
動作は、定数 (静的) 動作や時間 (時計など) などのいくつかのプリミティブから、順次および並列的に組み合わせて構築されます。 n 動作は、n 項関数 (静的値に) を「ポイントごとに」、つまり時間の経過とともに継続的に適用することによって結合されます。
離散現象を説明するには、別のタイプ (ファミリー) の「イベント」を用意し、それぞれに発生の流れ (有限または無限) を持たせます。それぞれの出来事には時間と値が関連付けられています。
すべての行動や出来事を構築するための構成語彙を思いつくには、いくつかの例を試してみてください。より一般的/単純な部分に分解し続けます。
しっかりした基盤の上にいることを知るために、表示意味論の手法を使用して、モデル全体に構成的な基盤を与えます。これは、(a) 各型には、対応する単純かつ正確な数学的型の「意味」があり、( b) 各プリミティブと演算子は、構成要素の意味に応じて単純かつ正確な意味を持ちます。決して、決して 探索プロセスに実装に関する考慮事項を組み込んでください。この説明が意味不明な場合は、(a) を参照してください。 型クラス射による表示設計, 、(b) プッシュプル関数型リアクティブ プログラミング (実装ビットを無視)、および (c) 表示意味論 Haskell ウィキブック ページ. 。指示意味論には 2 つの部分があることに注意してください。その 2 人の創始者 Christopher Strachey と Dana Scott は次のように述べています。より簡単で便利な Strachey の部分と、(ソフトウェア設計にとって) 難しくてあまり役に立たない Scott の部分です。
これらの原則に従えば、多かれ少なかれ FRP の精神に沿ったものが得られると思います。
これらの原則をどこで入手したのでしょうか?ソフトウェア設計において、私はいつも同じ質問をします。"それはどういう意味ですか?"。表示意味論は、この質問に対する正確な枠組みと、私の美学に合った枠組みを与えてくれました (操作意味論や公理意味論とは異なり、どちらも私に満足のいくものではありません)。そこで私は、行動とは何だろうかと自問しました。私はすぐに、命令型計算の時間的に離散的な性質が特定のスタイルへの適応であることに気づきました。 機械, 、行動そのものの自然な説明ではありません。私が思いつく行動の最も単純で正確な説明は、単純に「(連続)時間の関数」です。これが私のモデルです。嬉しいことに、このモデルは継続的で決定的な同時実行を簡単かつ適切に処理します。
このモデルを正しく効率的に実装するのは非常に困難でしたが、それはまた別の話です。
他のヒント
純粋な関数型プログラミングでは、副作用はありません。多くの種類のソフトウェア(たとえば、ユーザーインタラクションを伴うもの)では、何らかのレベルで副作用が必要です。
機能的なスタイルを維持したまま、振る舞いのような副作用を得る1つの方法は、機能的なリアクティブプログラミングを使用することです。これは、関数型プログラミングと反応型プログラミングの組み合わせです。 (リンク先のウィキペディアの記事は後者についてです。)
リアクティブプログラミングの基本的な考え方は、値<!> quot; over time <!> quot;を表す特定のデータ型があるということです。これらの経時変化の値を含む計算には、経時変化する値が含まれます。
たとえば、マウス座標を時間の整数値のペアとして表すことができます。次のようなものがあるとしましょう(これは擬似コードです):
x = <mouse-x>;
y = <mouse-y>;
いつでも、xとyはマウスの座標を持ちます。非リアクティブプログラミングとは異なり、この割り当てを行う必要があるのは1回だけで、xおよびy変数は<!> quot; upto date <!> quot;自動的に。これが、リアクティブプログラミングと関数型プログラミングが非常にうまく機能する理由です。リアクティブプログラミングを使用すると、変数を変更する必要がなくなり、変数の変更で達成できることの多くを実行できます。
これに基づいていくつかの計算を行うと、結果の値も時間とともに変化する値になります。例:
minX = x - 16;
minY = y - 16;
maxX = x + 16;
maxY = y + 16;
この例では、minX
は常にマウスポインターのx座標より16小さくなります。リアクティブ対応ライブラリを使用すると、次のように言うことができます。
rectangle(minX, minY, maxX, maxY)
また、マウスポインターの周囲に32x32ボックスが描画され、移動する場所を追跡します。
こちらは非常に優れた機能に関する論文ですリアクティブプログラミング。
プログラムがスプレッドシートであり、すべての変数がセルであると想像することは、それがどのようなものであるかについての最初の直観に到達する簡単な方法です。スプレッドシート内のセルのいずれかが変更されると、そのセルを参照するセルも変更されます。 FRPでも同じです。ここで、いくつかのセルがそれ自体で変化する(または、むしろ外の世界から取得される)と想像してください。GUIの状況では、マウスの位置が良い例です。
それは必然的にかなり多くを見逃します。このメタファーは、実際にFRPシステムを使用すると、かなり速く壊れます。 1つには、通常、個別のイベント(たとえば、クリックされるマウス)をモデル化する試みがあります。これがどのようなものかを説明するためだけにここに置いています。
私にとっては、シンボルの2つの異なる意味=
:
- 数学では
x = sin(t)
は、x
がsin(t)
の異なる名前であることを意味します。したがって、x + y
と記述することはsin(t) + y
と同じです。この点では、関数型リアクティブプログラミングは数学に似ています。t
を記述すると、使用時の<=>の値に関係なく計算されます。 - Cライクなプログラミング言語(命令型言語)では、<=>は割り当てです。つまり、<=>は、割り当て時に取得したの値 <=>を格納します。
OK、背景知識とあなたが指摘したウィキペディアのページを読むと、リアクティブプログラミングはデータフローコンピューティングのようなものですが、特定の外部<!> quot; stimuli <!> quot;一連のノードをトリガーして、それらの計算を起動および実行します。
これは、たとえばユーザーインターフェイスコントロール(音楽再生アプリケーションの音量コントロールなど)に触れると、さまざまな表示項目とオーディオ出力の実際の音量を更新する必要があるUIデザインに非常に適しています。有向グラフのノードに関連付けられた値の変更に対応するボリューム(スライダーなど)を変更する場合。
<!> quot; volume value <!> quotからのエッジを持つさまざまなノード。ノードが自動的にトリガーされ、必要な計算と更新がアプリケーション全体に自然に波及します。アプリケーション<!> quot; reacts <!> quot;ユーザーの刺激に。関数型リアクティブプログラミングは、関数型言語で、または一般的に関数型プログラミングパラダイム内でこのアイデアを実装することです。
<!> quot; dataflow computing <!> quot;の詳細については、Wikipediaでこれらの2つの単語を検索するか、お気に入りの検索エンジンを使用してください。一般的な考え方は次のとおりです。プログラムはノードの有向グラフであり、それぞれがいくつかの簡単な計算を実行します。これらのノードは、いくつかのノードの出力を他のノードの入力に提供するグラフリンクによって互いに接続されています。
ノードが起動または計算を実行すると、その出力に接続されたノードには対応する入力があります<!> quot; triggered <!> quot;または<!> quot; marked <!> quot;。すべての入力がトリガー/マーク/使用可能になっているノードが自動的に起動します。グラフは、リアクティブプログラミングの実装方法に応じて、暗黙的または明示的になります。
ノードは並行して起動していると見なすことができますが、多くの場合、ノードは連続して、または限られた並列性で実行されます(たとえば、いくつかのスレッドが実行する場合があります)。有名な例は Manchester Dataflow Machine で、これは(IIRC)がタグ付きデータアーキテクチャを使用して1つ以上の実行ユニットを介してグラフ内のノードの実行をスケジュールします。データフローコンピューティングは、非同期的に計算をトリガーして計算のカスケードを発生させる状況に適しています。1つまたは複数のクロックで実行を制御しようとするよりも優れています。
リアクティブプログラミングは、この<!> quot;実行のカスケード<!> quot;をインポートします。データフローのような方法でプログラムを考えているようですが、ノードの一部が<!> quot; outside world <!> quotにフックされているという条件があります。そして、感覚のようなノードが変化すると、実行のカスケードがトリガーされます。その場合、プログラムの実行は、複雑な反射アークに類似したもののように見えます。プログラムは、刺激間で基本的に固着する場合とそうでない場合があります。また、刺激間で基本的に固着状態になることもあります。
<!> quot; non-reactive <!> quot;プログラミングとは、実行の流れと外部入力との関係について非常に異なる視点でプログラミングすることです。人々は外部入力に反応する何かを言うように誘惑される可能性が高いので、それはいくらか主観的である可能性があります<!> quot; reacts <!> quot;彼らへ。しかし、物事の精神を見ると、一定の間隔でイベントキューをポーリングし、関数(またはスレッド)に見つかったイベントをディスパッチするプログラムは、あまり反応的ではありません(一定の間隔でユーザー入力のみに対応するため)。繰り返しになりますが、それはここでの精神です。非常に低いレベルでシステムにポーリング間隔の速いポーリング実装を置き、その上で事後対応的にプログラムすることを想像できます。
FRPについてたくさんのページを読んだ後、ついに見つけました これ FRPについて啓発的に書いて、ようやくFRPとは何なのかを理解することができました。
以下にハインリヒ・アプフェルムス(反応性バナナの著者)を引用します。
関数型リアクティブプログラミングの本質とは何でしょうか?
よくある答えは、「FRPは、変化可能な状態ではなく時変関数の観点からシステムを記述することに関するものであり、それは確かに間違っていないということです。これが意味論的な観点です。しかし、私の意見では、より深く、より満足のいく答えは、次の純粋に構文的な基準によって与えられます。
関数型リアクティブ プログラミングの本質は、宣言時に値の動的な動作を完全に指定することです。
たとえば、カウンターの例を見てみましょう。カウンターのインクリメントまたはデクリメントに使用できる「アップ」と「ダウン」というラベルの2つのボタンがあります。必須では、最初に初期値を指定し、ボタンが押されるたびに変更します。このようなもの:
counter := 0 -- initial value on buttonUp = (counter := counter + 1) -- change it later on buttonDown = (counter := counter - 1)
ポイントは、宣言の時点で、カウンターの初期値のみが指定されていることです。カウンターの動的な動作は、プログラムテキストの残りの部分で暗黙的です。対照的に、機能的な反応性プログラミングは、次のような宣言時に動的な動作全体を指定します。
counter :: Behavior Int counter = accumulate ($) 0 (fmap (+1) eventUp `union` fmap (subtract 1) eventDown)
カウンターのダイナミクスを理解したいときはいつでも、その定義を見るだけです。それに起こる可能性のあるものはすべて、右側に表示されます。これは、その後の宣言が以前に宣言された値の動的な動作を変える可能性がある命令的なアプローチと非常に対照的です。
それで、 私の理解 FRP プログラムは一連の方程式です。
j
離散的です:1、2、3、4...
f
に依存します t
これには外部刺激をモデル化する可能性が組み込まれています
プログラムのすべての状態は変数にカプセル化されます x_i
FRP ライブラリは進行時間を処理します。つまり、 j
に j+1
.
これらの方程式については、次の記事でさらに詳しく説明します。 これ ビデオ。
編集:
最初の回答から約 2 年が経ち、最近、FRP の実装には別の重要な側面があるという結論に達しました。彼らは重要な実践的な問題を解決する必要があります (そして通常はそうします)。 キャッシュの無効化.
の方程式は、 x_i
-s は依存関係グラフを記述します。そのうちのいくつかが x_i
時間とともに変化する j
他のすべてではありません x_i'
の値 j+1
更新する必要があるため、すべての依存関係を再計算する必要はありません。 x_i'
~から独立しているかもしれない x_i
.
さらに、 x_i
変更される -s は段階的に更新できます。たとえば、マップ操作を考えてみましょう f=g.map(_+1)
Scala では、 f
そして g
は List
の Ints
. 。ここ f
に対応 x_i(t_j)
そして g
は x_j(t_j)
. 。ここで要素を先頭に追加すると、 g
それならそれを実行するのは無駄です map
内のすべての要素に対する操作 g
. 。一部の FRP 実装 (例: リフレックスFRP)この問題を解決することを目的としています。この問題は次のようにも知られています。 インクリメンタルコンピューティング。
言い換えれば、行動( x_i
FRP の -s ) は、キャッシュされた計算と考えることができます。これらのキャッシュを効率的に無効にして再計算するのが FRP エンジンの役割です ( x_i
-s) いくつかの場合、 f_i
-sは変わります。
論文 単純に効率的な機能的反応性 by Conal Elliott( ダイレクトPDF 、233 <!> nbsp; KB)かなり良い紹介です。対応するライブラリも動作します。
この論文は、別の論文 プッシュプル関数型リアクティブプログラミング (直接PDF 、 286 <!> nbsp; KB)。
免責事項:私の答えは、rx.js-Javascriptの「リアクティブプログラミング」ライブラリのコンテキストです。
関数型プログラミングでは、コレクションの各アイテムを反復処理する代わりに、コレクション自体に高次関数(HoF)を適用します。したがって、FRPの背後にある考え方は、個々のイベントを処理する代わりに、イベントのストリーム(observable *で実装)を作成し、代わりにHoFを適用するというものです。このようにして、パブリッシャーとサブスクライバーを接続するデータパイプラインとしてシステムを視覚化できます。
オブザーバブルを使用する主な利点は次のとおりです。
i)コードから状態を抽象化します。たとえば、「n」番目のイベントごとにのみイベントハンドラーを起動する場合、最初の「n」イベント後に起動を停止する場合、または最初の「n 'イベントでは、カウンターを設定、更新、チェックする代わりに、HoF(filter、takeUntil、skipそれぞれ)を使用できます。
ii)コードの局所性を改善します-コンポーネントの状態を変更する5つの異なるイベントハンドラーがある場合、それらのオブザーバブルをマージし、マージされたオブザーバブルに1つのイベントハンドラーを代わりに定義して、5つのイベントハンドラーを効果的に1に結合できますシステム全体でどのイベントがコンポーネントに影響を与える可能性があるかを簡単に判断できます。これは、すべてのイベントが単一のハンドラーに存在するためです。
- ObservableはIterableの双対です。
Iterableは遅延消費シーケンスです-各アイテムは使用するたびにイテレータによってプルされるため、列挙はコンシューマによって駆動されます。
オブザーバブルは遅延生成シーケンスです-各アイテムはシーケンスに追加されるたびにオブザーバーにプッシュされるため、列挙はプロデューサーによって駆動されます。
おい、これは驚くべき素晴らしいアイデアだ! 1998年になぜこのことを知りませんでしたか?とにかく、 Fran チュートリアルの私の解釈です。提案は大歓迎です。これに基づいてゲームエンジンを開始することを考えています。
import pygame
from pygame.surface import Surface
from pygame.sprite import Sprite, Group
from pygame.locals import *
from time import time as epoch_delta
from math import sin, pi
from copy import copy
pygame.init()
screen = pygame.display.set_mode((600,400))
pygame.display.set_caption('Functional Reactive System Demo')
class Time:
def __float__(self):
return epoch_delta()
time = Time()
class Function:
def __init__(self, var, func, phase = 0., scale = 1., offset = 0.):
self.var = var
self.func = func
self.phase = phase
self.scale = scale
self.offset = offset
def copy(self):
return copy(self)
def __float__(self):
return self.func(float(self.var) + float(self.phase)) * float(self.scale) + float(self.offset)
def __int__(self):
return int(float(self))
def __add__(self, n):
result = self.copy()
result.offset += n
return result
def __mul__(self, n):
result = self.copy()
result.scale += n
return result
def __inv__(self):
result = self.copy()
result.scale *= -1.
return result
def __abs__(self):
return Function(self, abs)
def FuncTime(func, phase = 0., scale = 1., offset = 0.):
global time
return Function(time, func, phase, scale, offset)
def SinTime(phase = 0., scale = 1., offset = 0.):
return FuncTime(sin, phase, scale, offset)
sin_time = SinTime()
def CosTime(phase = 0., scale = 1., offset = 0.):
phase += pi / 2.
return SinTime(phase, scale, offset)
cos_time = CosTime()
class Circle:
def __init__(self, x, y, radius):
self.x = x
self.y = y
self.radius = radius
@property
def size(self):
return [self.radius * 2] * 2
circle = Circle(
x = cos_time * 200 + 250,
y = abs(sin_time) * 200 + 50,
radius = 50)
class CircleView(Sprite):
def __init__(self, model, color = (255, 0, 0)):
Sprite.__init__(self)
self.color = color
self.model = model
self.image = Surface([model.radius * 2] * 2).convert_alpha()
self.rect = self.image.get_rect()
pygame.draw.ellipse(self.image, self.color, self.rect)
def update(self):
self.rect[:] = int(self.model.x), int(self.model.y), self.model.radius * 2, self.model.radius * 2
circle_view = CircleView(circle)
sprites = Group(circle_view)
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == KEYDOWN and event.key == K_ESCAPE:
running = False
screen.fill((0, 0, 0))
sprites.update()
sprites.draw(screen)
pygame.display.flip()
pygame.quit()
要するに:すべてのコンポーネントを数値のように扱うことができる場合、システム全体を数学の方程式のように扱うことができますよね?
Paul Hudakの本、 Haskell School of Expression は、 Haskellの入門書ですが、FRPにもかなりの時間を費やしています。 FRPの初心者の場合は、FRPの仕組みを理解するために強くお勧めします。
この本の新しい書き直しのように見えるものもあります(2011年リリース、2014年更新)、ハスケル音楽学校。
これまでの回答によれば、数学的には、単に上位で考えるだけのようです。型 X を持つ値 x を考える代わりに、関数 x を考えます: T <!># 8594; X 、ここで T は時間のタイプで、自然数、整数、または連続体です。プログラミング言語で y := x + 1と書くと、実際には方程式 y ( t )= x ( t )+ 1。
前述のスプレッドシートのように動作します。通常、イベント駆動型フレームワークに基づいています。
すべての<!> quot; paradigms <!> quot;と同様、新しさは議論の余地があります。
アクターの分散フローネットワークの経験から、ノードのネットワーク全体での状態の一貫性という一般的な問題の犠牲になりやすくなります。つまり、多くの振動が発生し、奇妙なループに陥ります。
一部のセマンティクスは参照ループまたはブロードキャストを意味するため、これを回避するのは難しく、アクターのネットワークが予測不可能な状態に収束する(または収束しない)ため、非常に混chaとなる可能性があります。
同様に、エッジは明確に定義されていても、グローバル状態はソリューションから遠ざかるため、一部の状態に到達しない場合があります。 2 + 2は、2が2になったとき、およびそのように留まったかどうかによって、4になることもあれば、そうでないこともあります。スプレッドシートには、同期クロックとループ検出があります。分散アクターは通常そうしません。
楽しい:)。
FRPについてのClojure subredditに関するこの素晴らしいビデオを見つけました。 Clojureを知らなくても理解するのは非常に簡単です。
動画は次のとおりです。 http://www.youtube.com/watch?v=nket0K1RXU4
後半でビデオが参照するソースは次のとおりです。 https://github.com/Cicayda/yolk-examples/blob/master/src/yolk_examples/client/autocomplete.cljs
この記事は、これまでに見た中で最も明確かつ明確な説明です。
記事からの引用:
リアクティブプログラミングは、非同期データストリームを使用したプログラミングです。
さらに、これらのストリームを結合、作成、フィルタリングするためのすばらしいツールボックスが提供されます。
記事の一部である素晴らしい図の例を次に示します。
時間の経過に伴う数学的データ変換(または時間の無視)に関するものです。
コードでは、これは機能的な純度と宣言型プログラミングを意味します。
状態バグは、標準の命令型パラダイムでは大きな問題です。コードのさまざまなビットは、異なる<!> quot; times <!> quotで共有状態を変更する場合があります。プログラムの実行中。これは対処が困難です。
FRPでは、宣言型プログラミングのように、データがある状態から別の状態にどのように変換され、何がトリガーされるかを記述します。これにより、関数は入力に単純に反応し、現在の値を使用して新しい値を作成するため、時間を無視できます。これは、状態が変換ノードのグラフ(またはツリー)に含まれ、機能的に純粋であることを意味します。
これにより、複雑さとデバッグ時間が大幅に削減されます。
数学のA = B + CとプログラムのA = B + Cの違いを考えてください。 数学では、決して変わらない関係を記述しています。プログラムでは、<!> quot; Right now <!> quot; AはB + Cです。ただし、次のコマンドはB ++である可能性があり、その場合、AはB + Cと等しくありません。数学または宣言型プログラミングでは、どの時点で質問しても、Aは常にB + Cと等しくなります。
そのため、共有状態の複雑さを取り除き、時間の経過とともに値を変更します。あなたのプログラムは推論するのがはるかに簡単です。
EventStreamは、EventStream +何らかの変換関数です。
動作は、EventStream +メモリ内の値です。
イベントが発生すると、変換関数を実行して値が更新されます。これが生成する値は、動作メモリに保存されます。
振る舞いを構成して、他のN個の振る舞いを変換した新しい振る舞いを生成できます。この合成値は、入力イベント(動作)が発生すると再計算されます。
<!> quot;オブザーバーはステートレスであるため、ドラッグの例のようにステートマシンをシミュレートするためにオブザーバーのいくつかが必要になることがよくあります。上記の変数パスなど、関係するすべてのオブザーバーがアクセスできる状態を保存する必要があります。<!> quot;
引用元-オブザーバーパターンの廃止 http://infoscience.epfl.ch/record/148043/files/DeprecatingObserversTR2010。 pdf
リアクティブプログラミングに関する簡潔で明確な説明は、 Cyclejs-リアクティブプログラミングに記載されています。シンプルで視覚的なサンプル。
[モジュール/コンポーネント/オブジェクト] 反応的は、完全に責任があることを意味します 外部イベントに反応して独自の状態を管理するため。
このアプローチの利点は何ですか? 制御の反転、 主に[モジュール/コンポーネント/オブジェクト]がそれ自体に責任を持ち、パブリックメソッドに対してプライベートメソッドを使用してカプセル化を改善するためです。
これは良い出発点であり、完全な知識源ではありません。そこから、より複雑で深い論文にジャンプできます。
Rx、Reactive Extensions for .NETをご覧ください。 IEnumerableを使用すると、基本的にストリームから「プル」することになります。 IQueryable / IEnumerableに対するLinqクエリは、セットから結果を「吸い取る」セット操作です。ただし、IObservableを介した同じ演算子を使用すると、「反応する」Linqクエリを作成できます。
たとえば、次のようなLinqクエリを書くことができます (MyObservableSetOfMouseMovementsのmから ここで、m.X <!> lt; 100およびm.Y <!> lt; 100 新しいPoint(m.X、m.Y))を選択します。
Rx拡張機能を使用すると、それだけです。マウスの動きの着信ストリームに反応して、100,100ボックスにいるときはいつでも描画するUIコードがあります...
FRPは、関数型プログラミング(すべての概念に基づいて構築されたプログラミングパラダイムは機能です)とリアクティブプログラミングパラダイム(すべてがストリームであるという考えに基づいて構築された(観測者および観測可能な哲学))の組み合わせです。それは世界最高のはずです。
リアクティブプログラミングに関するAndre Staltzの投稿をご覧ください。