FRPの川つくった
GUI作るの辛い。オブジェクト指向的コンポーネントは限界がある。時代はやっぱFRPか?と思ってRx.jsとbacon.jsとか触ってみたんだけど。難しすぎて発狂した。
FRP
エクセルのセルがなんか他のセルの状態によって変化するようなやつ(雑)
bacon.jsが難しすぎる
こういうのがたくさんある。
本当にやりたいことは?
- ストリーム作って
- 合流させて
- その値が変化したタイミングを知りたい
- (ついでにメモリ圧迫したくない)
- (あと依存なしでnodeでもブラウザでも)
川の流れをつくった
new Kawa.Stream(初期値, reduce関数)
でストリームを作る
sumStream = new Kawa.Stream 0, (v, sum) -> v + sum # 初期値と集約関数 sumStream.onChange (v) => console.log v # addSourceでストリームに値を追加する sumStream.addSource 1 # 1 sumStream.addSource 2 # 3
reduce関数を省略したら最後にaddSourceされた値を返す関数(val)-> val
をデフォルトで使う。
Kawa.merge
でストリームを合流させた新しい川のストリームを作れる。
s1 = new Kawa.Stream 0 s2 = new Kawa.Stream 0 merged = Kawa.merge 0, [s1, s2], ([v1, v2], last) -> v1 + v2 merged.onChange (v) -> console.log 'merged:', v s1.addSource 2 # -> merged: 2 s2.addSource 2 # -> merged: 4
s1, s2どっちの値が変わっても、merged.onChangeは発火する。(同値チェックはしてない。プリミティブ値以外が見れなくなるため)
川が特定の状態になったらコールバックを発火したい。
Kawa.when [s1, s2], (([v1, v2]) -> v1 is v2 * 2), -> console.log 'fullfilled!' s1.addSource 2 s2.addSource 1
s1がs2の二倍になったら発火する。whenじゃなくてonceだったら一回しか実行されない。
すべての川のStreamはdisposeで破棄可能。メモリを漏らさない。
s1 = new Kawa.Stream 0 s2 = new Kawa.Stream 0 merged = Kawa.merge 0, [s1, s2], ([v1, v2], last) -> v1 + v2 waiter = Kawa.when [s1, s2], (([v1, v2]) -> v1 is v2 * 2), -> console.log 'fullfilled!' # ... merged.dispose() s1.dispose() s2.dispose() waiter.dispose()
まとめ
- bacon.jsは難しすぎる
- 自分で単機能な実装したら150行だった
- エクセルとか実装したいときに便利だと思う
- 普通の人間はエクセルを実装しない