FRP を使った航空券予約サンプル
抽象的なビジネスルールの操作
- FRP は 宣言型プログラミング スタイルを使用するため、プログラムが何をするかでなく、プログラムが何であるかを考えることになる。
- merge が提供するストリームは、入力ストリームのどちらかが発火した場合に、それと同時に出力ストリームにイベントが出現するようなストリームである。
-
FRP の処理はトランザクション型のコンテキストで実行される。基本的な考え方は、データベースで使用されるトランザクションと同じである。
-
Sodiumでは、入力値がストリームやセルに格納されると、トランザクションが自動的に開始される。その入力の結果として発生する状態の変更はすべて同じトランザクションの中で実行される。
-
通常、外部ストリームは同時性を生み出さない。このため、同時イベントを引き起こすのは、ほとんどの場合、同一の入力ストリームの変更を表す2 つのストリームである
- FRP の概念では、「マウスクリック」、「選択解除」、「選択」の3 つのイベントがまさに同時に発生するため、それらが発生した順序を特定することは不可能である
-
FRP システムにはそれぞれ同時イベントをマージするための独自のポリシーがある
-
Sodium
-
2 つの入力ストリームで複数の入力イベントが同時に発生する場合、それらはmerge によって1 つにまとめられる。merge は、2 つ目の引数として結合関数を受け取る
-
結合関数は、入力イベントが同時に発生しない状況では使用されない。
-
このポリシーの素晴らしい効果
-
与えられたストリームにおいてトランザクションごとに発生するイベントは1つだけである
-
トランザクションの中では、イベントの処理順序のようなものは存在しない。同じトランザクションにおいて様々なストリームから発生するイベントはどれも、それらの間の順序を特定できない点では、まさに同時に発生する。
-
FRP の中には、同時イベントの結合を強要せず、ストリームごとに複数のイベントを許可するものがある。
RxSwift では結合関数は渡さない (Observable.of().merge())
- そうしたシステムは「真のFRP システム」ではない。本書の執筆時点では、Rx(Reactive Extensions)と呼ばれるシステムと、そこから着想を得ているシステムの多くは、この要件を満たしていない。結果として生じる問題は理論とは無関係であるため、この状況が変化することを願っている
- Sodium の Stream クラスには、ストリームのコレクションで使用できる merge も定義されている。どの FRP システムにも、これに相当するものがある。
RxSwift では Observable.from().merge()
- merge の実装では、これ以上入力を受け取らないことがわかるまで、一時ストレージにイベントを格納しておく必要がある。その後、イベントを出力する。
- イベントを2つ以上受け取った場合は、指定された関数を使ってそれらを結合する。
- イベントが1つだけの場合は、それを出力する。
関数は参照透過的でなければならない ごまかしは常に泣きをみることになる
hold プリミティブは RxSwift では BehaviorSubject().subscribe() にあたる
- セルがモデル化するのは、時間とともに変化する値である
- セルには常に値があり、その値はいつでもサンプリグできる
- ストリームの値は、ストリームが発火した瞬間に割り当てられたものだけである
- 「セルはメモリ」
- hold は、ストリームと初期値を受け取り、その初期値が最初から含まれたセルを作成する。その後、ストリームが発火するたびに、セルの値がストリームイベントの値に変更される
セルは RxSwift でいうと BehaviorSubject
snapshot は RxSwift でいうと withLatestFrom()