Evan Czaplicki「脱FRP。またはThe Elm ArchitectureからSignalを消した件」
elm-lang.orgの2016.5.10のブログエントリ farewell-to-frp
ElmクリエータのEvanによる最新版0.17
のアナウンス
- 「Reactiveとか、非同期データストリームとかObservableとか、まあええけど、敷居上げすぎじゃね?」
- 「じゃあSignal外して」「脱FRPしとくか」(今回)
- 「WebAssembly来るかも?」
- 「じゃあサクッと移行できるようにJSとのインフェース最小にしとくか」
- 「いつでもどこでも脱AltJSできるように準備しとくか」
- 「クロスコンパイルとかはいいわ」
- 「OSS化しましたので皆様使って頂けたら。。。。」
- 「神頼み?それじゃあエコシステムはできんわ」
- 「フルタイムでElm開発できるとこに入っとく」(Preziにjoin)
- 「Chigaco大でFunctional Programmingの講義をElmで通してもらった」
- 「インターンとか一緒にやってくれる人ガンガン増やせるとこいく」(NoRedInkにjoin)
- 「団体もつくっとくか」(Elm Software Foundation)
- 「Reduxにあんな形で丸パクリされたのは痛恨のミスや」「アイディアを出すタイミングを気をつけよ」
- 「カンファレンスやっとこか」(Elm-Conf 2016)
というノリで、「使える言語」「使いやすい言語」ために手を打っていくところが面白い
以下斜め読んだ内容
- The Elm Architectureのおさらい
- webアプリ作るためのシンプルなパターン
- Elmでコード書くときの標準的やりかた
- 他言語に輸出された
- reduxとか
- JS界隈でも広まってきてる
- 「成功した」と呼べるレベルに到達
- Q:The Elm Architectureに沿って、websocketやGraphQLやgeolocationどう使う?
- A:
Subscription
使え- コミュニティ内でこういう声は耳にしてきた
Subscription
は自信作。いい感じににwebsocketつかえる- 今日(=2016.5.10)リリースするElm
0.17
で追加した
Subscription
入れると。。。- コンポーネントはメッセージを待受するだけに
- ライブラリが裏で大量の手強いリソース管理をやってくれてる
Subscription
でwebsocketが手軽に使える点は、エントリで後述する
Elmの学びやすさ・使いやすさの飛躍的な向上
- (
Subscription
などが入った)Elm0.17
リリースの意味
- (
- 少し前までElmには、
Signal
、Address
、Port
というのがありまして。。。- こいつらがElmの敷居を高くしていた。
Subscription
を次のリリースでElmに入れてみようか、と考えてるときに気付いたSignal
(とかの難解なコンセプト)は無くてもいいじゃん- もっとシンプルなコンセプトに分解していけば、Signal引退できる
- (補足)
port
は0.17
でも現役- ElmとJSの通信で使う
- JavaScript and Ports · An Introduction to Elm
- 「Elmを使いこなす」ために理解しないといけないコンセプトの数
Signal
が引退すれば、この数をぐっと減らせる
- 「使いやすさ」のためにElmをデザインしてる
- これは思いがけず開けた道筋。かなりうれしい展開。
- 「皆さん注目!」的な言い方を敢えてしてみると。。。
Signal
に関係してるもの全部引退- もっとシンプル、もっと優れたものに置き換え。
Signal
引退をElm界隈でアナウンスしてみた- 2パターンの反応
- 反応1:クレージー。コードは動くのか
- 回答1:95%(俺調べ)のコードはそのままで動く
- 移行ガイド用意した
- elm-platform/0.17.md at master · elm-lang/elm-platform
- 数カ所コードベース変更するが、大掛かりな作業にはならない
- (補足)
- 割と実態に沿ってる。かなり詳しいDiffつきの「移行してみた」エントリ書いてる人がいて参考になる
- Typed up CRUD SPA with Haskell and Elm - Part 5: Elm 0.17 Upgrade
- 反応2:お前は何言ってるんだ? FRPとかSignalとか何それ
- 回答2:「知らん」でOK
- 今回のリリース(
0.17
)に直結する話。 - Elmには不要になった
- 今回のリリース(
- あれこれ回答するよりも、新しいElmがどう動くかを見せた方がいい。
- 閑話休題
subscription
以外の0.17
のおすすめ紹介- HTMLレンダリングを高速化(ベンチマークは後で出す)
- web platformのテクノロジーを簡単に使えるライブラリを追加
- geolocation
- Page Visibility API
- websockets
- コンパイル最適化
- outputのjsのサイズをダウン
- outputされるjs
- closure compilerに通せる
- RequireJSサポート
- CommonJSサポート
- GraphQLやPhoenix(Elixir)のようなサービスと連携するための機能
- ドキュメント改善:Gitbookベースに
- JSONデコードエラー時のメッセージ出力の改善
subscription
例その1。現在時刻の待受
- コンポーネントがメッセージ待受をサポートできるようにするための方法
subscription
が一つのやりかた
- コンポーネントがsubscribeする対象
- 現在時刻
- 位置の変化
- websocketメッセージ
- etc..
- SVGによるアナログ時計を使って説明する
- SVG時計の基礎は、時間へのsubscribe
- subscriptionの最もシンプルな例
- とりあえずSVG時計のソースコードをざっと見てもらいたい
- 典型的なElmコード
-- 0.17以前と違う箇所はこの3行だけ subscriptions : Model -> Sub Msg subscriptions model = Time.every second Tick
- 与えられた
model
に対して、アクティブなsubscritpionがこれだけで記述されてる - 関数
Time.every
を使って、現在時刻へのsubscriptionを記述 - 現在時刻は毎秒更新
- 新しい時刻(ex
Tick 1462487781991
)はupdate関数に渡される - (補足)
- subscriptionは、
Sub msg
型(Sub
=Platform.Sub
) - 関数
Time.every
の型定義は、Time.every : Time -> (Time -> msg) -> Sub msg
- なので、
Time.every second Tick
は、Sub msg
型 - あと、
second
(Time.second
は)Time
型 Tick
はtype Msg = Tick Time
という型定義から、(Time -> msg)
型Tick 1462487781991
はMsg
型
Tick
は冗長にかけば、(\time -> Tick time)
、となる- つまり、
Time.every second (\time -> Tick time)
- subscriptionは、
- subscription以外の部分はすべては
0.17
以前と同じまま - 何かを待受してるだけなので、一番簡単な例
- 次は、もうちょっと複雑なシナリオで
例その2。websockets通信
- シンプルなchatクライアントdemo
- 送信されたメッセージを表示するだけの機能(荒れても困るので)
- ソースコード
- SVG時計と見比べると大変よく似てる
- よく似たコードだけど、このコードだけでwebsocket通信を管理してる
-- ソースコードで注目すべきはこの2行だけ -- こっちはメッセージを送信 WebSocket.send "ws://echo.websocket.org" input -- こっちはメッセージをsubscribeしてる WebSocket.listen "ws://echo.websocket.org" NewMessage
- 送信してるコード、subscribeしてるコードの共通してること
- chatサーバのアドレスを渡してる点
- 通信を助ける値を渡してる
WebSocket.listen
では渡されてるNewMessage
はMsg
型のタグを返す関数- (補足)
Msg
型の型定義は、type Msg = Input String | Send | NewMessage String
Union Types使って定義されてる
Input String
やSend
やNewMessage String
をタグと言う(らしい)- なのでUnion Typeと呼ばずに、Tagged Unionと言う人がいる
- (補足)
- サーバーから「hi」というメッセージを受け取り、
NewMessage "hi"
、をupdate関数に渡す - (補足)
WebSocket.listen
の型定義は、String -> (String -> msg) -> Sub msg
NewMessage
は、String -> msg
型の関数NewMessage "hi"
はMsg
型
- 自慢できること
- あれこれ細かい制御のためのコードを書かなくてもチャット機能を提供できてること
- sendしてlistenする。それだけ
- チャット機能をjsでやろうとすると。。。
- ひとつはブラウザAPIを直接触る
new WebSocket(...
するところから- コネクション開く
onerror
リスナーつけ忘れない- 切断されたら再接続するように書く
- いわゆるExponential Backoffの仕組みもいる
- 切断されてたらメッセージ送らないようにしないといけない
- ランタイムエラーになるから
- キューイングシステムも実装必要
- 切断時にpostされたメッセージを貯めとく
- さらに
- どのコンポーネントがwebsocket通信するかを考えて設計しないといけない
- 接続の切断についても適切な時間でやれるようにしないといけない
- JSライブラリを使う手もある
- 調べると2,000以上はある。npm検索で
- 最初の1、2個で当たりが出ることを祈りましょう
- ひとつはブラウザAPIを直接触る
- ElmのWebSocketパッケージを使うと。。。。
- websocket通信のための細々とした管理は自動的に行われる
- subscriptionが発生すれば自動接続
- subscribeがゼロになれば自動切断
- メッセージのキューイング、再接続はバックグラウンドで処理され、意識しないでいい
さらに学ぶためのリソース
- 公式ガイド
- http://guide.elm-lang.org/
- Elmと The Elm Architectureがやろうとしてることを知りたい人
- The Elm Architectureのセクションを一読してほしい
- 順序立てて
Suscription
を使った実装をやるとこまで書いてる
- 他にもいいサンプルある
- Elm経験者にはアップグレードガイド用意してる
- https://github.com/elm-lang/elm-platform/blob/master/upgrade-docs/0.17.md
- 公式ガイドもあわせて読んでほしい
- 今回のリリースで作り上げることに成功した、Elmの全てのパーツが見事にはまった仕組みの全容を、うまく説明できた自負がある
- ガイドの中で「The Elm Architecture」と「ports」の箇所が重要だと思う
- Slackチャンネル作った。活用してほしい
- Elm初心者が質問する場所、何か学ぶ場所として
0.16
以前のアプリを0.17
に移行させたい人の質問する場所として
さらばFRP
- このraycasterみたいな、楽しくなるプロジェクト
- シェアしたくなるプロジェクト
- プログラミングすることに熱中させてくれるプロジェクト
- Elmは、こういうプロジェクトを作っていける何か
- Elmを作ってる自分が自問してきたこと
- どうすればElmがもっとシンプルになるか
- どうすればElmが学びやすくなるか
- どうすればもっと楽しくなるか
- どうすればもっと素早くプロトタイプを作れるようになるか
- どうすればもっと信頼できる言語になるか
- こういった自問し続けてることが、Elmの設計哲学の中心にあり、Elmの成功の根幹にある
- 2011年頃に自分が卒論を書いてた頃の話
- http://elm-lang.org/papers/concurrent-frp.pdf
- たまたま"Functional Reactive Programming" (FRP)と呼ばれるニッチな学問領域に突入した
- FRPの手法をシンプルな形に落とし込むことを考えていた
- 結論として類似の関数型言語よりも学習しやすいものを作ることができた
Signal
は難解なコンセプトが折り重なったもの- Elmには必要ではなかった
- 「
Signal
はElmにある数少ない躓きポイント」- Elmを教えた経験のある人なら同意してくれるところ
- 「
Signal
によってElmは使やすくなった」- 類似言語との比較でならそうとも言える
Signal
はElmそのものを「やさしい」言語にはしなかった
- The Elm Architecture導入後
- 結構前から
Signal
はElmから削除可能だった- 「Elmはconcurrency重視」に舵を切っていたから
- cocurrency重視のアイディアの原型は自分の卒論に確認できる
0.15
でElmにTask
を導入してから、Elmの実装レベルでこの方向に進み出した
0.15
で導入されたスケジューラ- スケジューラはwork(?)の切り替えをサポートし、必要なときだけ実行させることができる
0.17
で大幅に改善された箇所- スケジューラはeffect managerの基盤
- さらに、effect managerが
Subscription
の基盤 - (補足)
- Elmでは、Effect(作用)はデータとして表現され、Elmランタイムが実行し、実行時に最適化を行う
- Effectの例:httpリクエスト、乱数取得、時刻取得、DB書込、etc..
- データとして表現され、Elmランタイムが最適化しながら実行するEffectは、
Subscription
とCommand
の2種類
- ドキュメントをもっと書き換えたいところ
- スケジューラ、effect managerの内部のことを深く知る必要はElmのエキスパートになるのに必要でない
- concurrencyの利点を即座に享受できることを目標にしてる
- この点は私の卒論Concurrent FRPの頃から変わってない
- ElmはFRP的ななにか?
- かつてそうだったが、今はそうでない
閑話休題:
Elmの今後
- Elm
0.17
開発初期の自分のヴィジョン- Foundation for planning "native" APIs in 0.17
- Elmはネイティブコードをどう取り扱うべきか
- 健全なパッケージのエコシステムはどういう形をとるか
- Elm
0.17
はこのヴィジョンの基礎になるリリース - 次に取り組む問題
- 1 webプラットフォームの全てをサポート
- 2 GraphQL, Elixir Phoenix, Firebaseなどのバックエンドのサポート
Commmands
とSubscription
では全てのケースはハンドリングできる- The Elm Architectureできちんと使えるパッケージを組み合わせて、一貫性をもたせることもできる
- これからこのへんの開発がどうなっていくのかが楽しみ
- 次の問題へどうアプローチするか
- これから新たに作っていくライブラリ開発に参加したい方へ
- そういう声をすでにもらってる
- コントリビュートしたいという情熱が素晴らしいアウトプットを生む
- 空回りなく、これが確実に起こるようにしておきたい
- そのために、一貫性のある開発プロセスをまず自分が作る
- それまで待っててほしい
- 次期リリースのために現時点でできるコントリビュート
- slackに参加して、elmコミュニティの動向を知ること
- 何かコントリビュートするときは常に事前にやるべきことだが
- slackに参加して、elmコミュニティの動向を知ること
thanks you
- @JustusAdam
elm-reactor
のnavigation画面の作り直し- 数年前に完了してた。ようやく公開できた
0.17
の設計に参加してくれた人たち- なんども繰り返して「これはあかんね」となったりもした
- それでも付き合ってくれて、優れたアウトプットしてくれた
- Elmコミュニティ
0.17
のリリースを辛抱強く待ってくれた- プレリリースのバイナリ使ってくれてバグ報告してくれた
- 特に、@gdotdesign、@colinmccabe、@lukewestby
- 改良したHTMLレンダラーの見つけにくいissueをキャッチ
- 優れたSSCCEを出してくれた