-
Notifications
You must be signed in to change notification settings - Fork 0
Shibuya.js in Kyoto
Arrow.js
Shibuya.js in Kyoto
motemen (motemen@gmail.com)
Arrow というのが Haskell 界隈で流行ってるらしい。
関数 (など) を矢印 (arrow) と見做して、矢印を連結することで処理を繋げていく
Arrow 同士を連結したものもまた arrow になる。
値を一つとって一つ返す関数から arrow を作る: Arrow(f)
Arrow.prototype.run(value)
は Arrow に値を一つ渡して実行するメソッド
CPS: Continuation Pasing Style
function(x) { // … return(x); } function(x, k) { // … k(x); }同期なコードも非同期なコードもコールバック形式にすることで同様に扱える。
Arrow(function(x) { return x + 1 }).run(1); // => 2Haskell の演算子をそのままメソッド名にしているため a['>>>'](b)
とする必要がある。@(a)[‘>>>’](b)@ とすることでより納得のいく形になります。:)
「値を a に渡し、その結果を b に渡す」arrow を作る演算子。
var aLoadIndex = Arrow.XHR('index.html');
var aAlert = Arrow(alert);
var aGetAlert = (aGetIndex)['>>>'](aAlert);
aGetAlert.run(); // index.html を xhr でロードして結果を alert する
値を複数の arrow で受け取る
((a)['***'](b)['***'](c)).run([1, 2, 3])
// a(1), b(2), c(3) が実行される
((aLoadJSON1)['&&&'](aLoadJSON2))['>>>'](aAlert).run()
// aLoadJSON1(undefined), aLoadJSON2(undefined)
// => [json1, json2]
非同期な arrow は全部の結果が返ってくるまで待つ
入力値によって複数の arrow のうち 1つを選択する
Arrow は値を 1つしか受け取れないため、値をラップするものが必要:
Arrow.Value.In(n)(x)
→ n 番目の arrow に値 x を渡す
((aHoge)['+++'](aFuga)['+++'](aPiyo))
.run(Arrow.Value.In(0)(x)) // => aHoge.run(x);
「a もしくは b, そのあと f もしくは g」という感じ
(((a)['|||'](b))['>>>']((f)['|||'](g)))
.run(Arrow.Value.In(1)(x)) // => g(b(x))
Arrow 内で例外が発生した場合はエラーオブジェクトが返ってくる
Arrow.Error = Arrow.Value.In(1);複数の arrow から、最初に返ってきた arrow の値を採用
全部返ってくるまで待つ &&&
とは違って…
((aLoadJSON1)['<+>'](aLoadJSON2)['<+>'](aLoadJSON3))['>>>'](aAlert).run()
// => json1 か json2 か json3, 一番早い 1つだけ
または
arrow.loop()arrow
の返した値をまた arrow
に渡してまた… という arrow
→ イベント処理などで使える (あとで実例を)
DOM イベントが発生したら次の arrow に進む
h3 Arrow.Delay(msec)
msec ミリ秒後に次の arrow に進む
何があっても次に続かない
→
(Arrow.Stop)['<+>'](aHoge)
は aHoge
と同じ
GitHub プレゼンテーションぐりもん
- (GitHub の wiki ページ上で) alt-p キーでプレゼンモードに入る
- プレゼンモードでは j, k でページを進む/戻る
- もちろんそれ以外のキーは無視
プレゼンモードの状態遷移図は…
プレゼンモードの arrow は
var aSlide =
(Arrow.Event(document, 'keydown'))
['>>>']
(
(aIsKey('j')['>>>'](aNextPage))
['<+>']
(aIsKey('k')['>>>'](aPrevPage))
['<+>']
(aNOP)
)
['>>>']
(aShowCurrentPage);
状態遷移図をそのままコードに落としただけ!(状態遷移図における矢印が arrow に対応している)
Arrow.Event(document, 'keydown')
により、ドキュメントで keydown
イベントが発生すると次の arrow にイベントオブジェクトが渡される
aIsKey(key)
というのは、キーイベントオブジェクトのキーが key
である時だけ次の arrow に処理を渡す arrow (というのを作っておく), これと <+>
を組み合わせると:
- “j” キーが押されたとき: aIsKey(‘j’)[‘>>>’](aNextPage) が実行される
- “k” キーが押されたとき: 上の arrow が次に進まないので、aIsKey(‘k’)[‘>>>’](aPrevPage) が実行される
- その他のキーが押されたとき: 上の arrow たちが次に進まないので、aNOP (何もしない arrow) に処理が移る
これらのうちどれかが実行されたあと、現在のページを表示する aShowCurrentPage
が実行される
プレゼンモードに入る前の状態遷移図は…
var aStart =
(Arrow.Event(document, 'keydown'))
['>>>']
(
(aIsKey('alt-p')['>>>'](Arrow.Value.In(0)))
['<+>']
(Arrow.Value.In(1))
)
['>>>']
(
((aSetupSlide)['>>>'](aSlide.loop()))
['+++']
(aNOP)
);
最初の arrow:
-
alt-p
が押されたら 0番目のルートを選ぶ - そうでなければ 1番目のルートを選ぶ
その結果を受け取る arrow:
- 0番目のルートでは: さっきの
aSlide
を繰り返す arrow (もう返ってこない) - 1番目のルートでは: 何もしない
これらの arrow を宣言した上で、
aStart.loop().run()とするとコードが動き始める…!
loop()
しているため aNOP
の後は最初に戻ってまた keydown
をリスンする
英語のメソッド名もあるけど見易いかどうかは…
var aSlide =
(Arrow.Event(document, 'keydown'))
.next(
(aIsKey('j').next(aNextPage))
.or
(aIsKey('k').next(aPrevPage))
.or
(aNOP)
)
.next(aShowCurrentPage);
自分でも半信半疑だったけどわりと便利な気がしてきた!