以下の記事は、Evanの許可を得て A Farewell to FRPを訳したものです。
訳者はElm初心者ですので、理解が足りてない箇所があるかと思われます。何か誤りやベターな記述がありましたら、ご指摘いただけると幸いです。
ちなみに、関数型リアクティブプログラミング全般の話ではなく、あくまでElmに関する話です。
ElmアーキテクチャはWebアプリを設計するためのシンプルな手法です。Elmを書くならばElmアーキテクチャに沿うのが普通ですし、ElmはReduxに影響を与えています。ElmアーキテクチャはもはやJavaScriptを書く際の手法としても人気になりつつあります。しかし、いまだにこんな疑問を耳にすることがあります。WebSocketをElmアーキテクチャで使うにはどうすればいいのか?あるいはGlaphQLは?あるいはGeolocationは?
__今日Elmのバージョン0.17がリリースされました。__そして、バージョン0.17には上記の疑問をうまく解決するようなsubscriptionsが導入されました。ライブラリがリソース管理を行っている間、subscriptionsはコンポーネントを待機させるのです。subscriptionがいかにしてWebSocketと簡潔に機能し合うかについては、後ほど見ていきましょう。
ここで注目すべきことは、__今やカンタンにElmを学び、そして使うことができるようになったということです。subscriptionを思いついた時、Elmにおけるすべての難しい概念(Signal、アドレス、ポート)は1つのシンプルな考えに集約できるのだと気付きました。Elmは使いやすさを重視しているので、より少ない概念への道筋が開けた時は喜びを感じました。分かりやすく言うと、 Signalに関する全てが、よりシンプルで良いものへと置き換えられたのです。__この知らせに対して、おそらく2つの反応があります。
- なんてこった。今までのコードは動くのか? おそらくコードの95%はまったく今までどおりで大丈夫です。アップデートプランを参考にしてください。アップデートはたいした問題ではありません。
- こいつは何を言っているんだ?関数型リアクティブプログラミング?Signal? 今回のリリースに関して、関数型リアクティブプログラミングやSignalについて学ぶ必要なんてないということです。Elmは今やカンタンなのです。
いずれにせよ、まずは新しいバージョンでElmがどのように動くのかをお見せするのが良いでしょう。Elmは今まで以上に多くのことが可能になりましたが、今まで以上にシンプルでもあります。Elmがこのような変化を遂げたことを嬉しく思いますし、Elmを楽しんでくださると幸いです。
Elm 0.17に含まれるその他の機能。
・ より速いHTMLレンダリング(数値はまもなく公開されます。)
・ Geolocation、ページ可視性、Web socketsのライブラリ
・ 生成されるJSが小さくなり、GoogleのClosure Compilerで動くようになりました。
・ 生成されるJSがRequireJSやCommonJSに対応。
・ GraphQLやElixir、Phoenixの代わりとなる機能。
・ 改善されたドキュメント。
・ JSONファイルのデコード失敗時の役立つメッセージ。
subscriptionとは何か?
subscriptionはコンポーネントに対して、メッセージを待たせるための手法です。たとえば、現在時刻や位置の変更、WebSocketのメッセージなどを定期的に受け取ることができます。
もっともシンプルなsubscriptionは時間です。時間のsubscriptionは、以下のSVG時計の根幹となるものです。
(略。本家を参照下さい。)
SVG時計のコードについては、こちらのソースコードをご覧ください。これはElmアーキテクチャに沿った典型的なElmのコードです。バージョン0.17で新しく追加されたのは、以下の定義部分だけです。
subscriptions : Model -> Sub Msg
subscriptions model =
Time.every second Tick
現在のModelをベースとして、すべてのアクティブなsubscriptionを説明していきます。上記の例では、Time.every関数は現在時刻のsubscriptionをセットアップします。このsubscriptionは毎秒ごとに更新されます。新しい時刻は、マウスクリックやHTTPリクエストの結果としてのメッセージと同じように、update関数に組み込まれます。
subscription以外のElmアーキテクチャに関するものはすべて従来通りです。コンポーネントを受動的に待たせる方がカンタンです。 さらに他のケースを見ていきましょう。
WebSocket
ここで、シンプルなチャットクライアントの例を見ていきましょう。人々が互いにおかしなことを言い合わないように、チャットサーバへとただメッセージを送る仕様としました。
(略。本家参照。)
サンプルのソースコードはこちらです。時計の例と非常に似ていますが、WebSocketのコネクション管理を行っています。考えをめぐらすべき箇所は以下の関数だけです。
WebSocket.send "ws://echo.websocket.org" input
WebSocket.listen "ws://echo.websocket.org" NewMessage
1行目はメッセージを送信する関数で、2行目がメッセージのsubscriptionです。どちらのケースでも、チャットサーバのアドレスとメッセージの値を与えています。send
には送信したい文字列だけを与えます。listen
はタグ付けを行う関数を持ちます。なので"hi"といったメッセージをサーバから受け取った時、NewMessage "hi"
としてupdate
関数に紐付けられます。
驚くべきことは、__セットアップのためにたくさんのトリックを行うこと無く、完璧に機能するチャットクライアントを作ることができた__ということです。ただ、sendとlistenを行う。それだけです。ただし、もしあなたがJavaScriptにおける2つの選択肢を知っていれば、さほど驚くことではないかもしれませんが。
-
ブラウザAPIを使う ― まず新たなWebSocketを立ち上げます。そして、コネクションを開きます。
onerror
をつけるのをお忘れなく。これはコネクションが落ちた時にexponential backoff形式で再接続を行います。そしてコネクションが落ちているときは決してメッセージをsend
しないでください。実行時エラーになります。キューに積んでおいて、後ほど送信する必要があります。キューが実装されたなら完成です。あとはただ、どのコンポーネントにWebSocketをもたせればいいのか決めるだけです。そして、閉じるべき時にソケットがきちんと閉じていることも確かめましょう。 - JSライブラリを使う ― ブラウザAPIを使うのはなんだか難しそうですね。では、同じようなライブラリを探してみましょう。2000以上もの選択肢があるみたいですね。幸い、私がいくつか試した所うまく動きました。
Elm用のWebSocketパッケージでは、コネクションの子守は自動的に行われます。コネクションはサブスクライブされたときにオープンになりますし、サブスクライブがされなくなるとクローズになります。キューや再接続に関する処理も裏側で行ってくれます。
もっとくわしく
手短ではありますが、以上がsubscriptionに関する導入でした。もし、ElmとElmアーキテクチャに何が起こっているのかを知りたければ、An Introduction to Elmをご覧下さい。Elmアーキテクチャに関する箇所は徐々にsubscription向けの内容になってきており、たくさんの好例が含まれています。
熟練のElmユーザはアップデートプランを読みましょう。An Introduction to Elmにもぜひ目を通してみてください。もちろんElmについては既にご存知でしょう。しかし、バージョン0.17においてElmの各機能がいかに素晴らしく結合されるかを、ガイドは実に上手く説明してくれるでしょう。特に、Elmアーキテクチャとportsの箇所は必見です。
最後に。いつでもSlackのElmチャンネルに来てくださいね!私たちは新しいことを学んだり、古いコードを書き換えようとする人々をぜひ助けたいです。質門を投げかけてみてください。
関数型リアクティブプログラミングにさよならを
Elmは楽しいプロジェクトを作成するためのものです。こちらのraicasterが良い例です。わくわくして人にシェアしたくなるようなプロジェクトです。プログラミングをすることがわくわくするようなプロジェクトです!そのため、私はいつでも自分に問いかけてきました。どうすればElmをシンプルにすることができるのか?Elmを学びやすいものにするにはどうすればいいのか?どうすればElmをより楽しいものにできるのか。プロトタイプしやすくするには?信頼性を高めるためには?
これらの疑問に対する私の執着がElmの設計思想と成功の肝であるように思われます。
2011年にこちらの論文に取りかかりはじめた時、関数型リアクティブプログラミング(FRP)と呼ばれる分野に出会いました。その手法をもっともシンプルな形式に落としこむことで、似たような関数型の言語よりも学びやすいものを作ることに私は帰着しました。難解な概念の積み重ねであるSignalは、Elmには必要なかったのです。
Elmを教えたことがある人ならきっと、Signalがつまづきやすいポイントの1つであることに同意してくれると思います。それらのつまづきやすい難所は、類似の言語に比べてElmをカンタンにしました。しかし、Elm自体をカンタンにしたわけではありません。
Elmアーキテクチャが現れた時、SignalはElmでのプログラミングにおいて全く必要のないものだと明確になりました。start-appパッケージを使えば、Signalはあとで学べばよくなります。start-appパッケージのリリースはそれによって何が起こるのかを知るための実験だったのです。結果は上々でした!多くの人びとが、Signalについてじっくりと学ばずとも、素晴らしいElmエンジニアとなったのです。Signalは不要だったのです。Elm 0.17は進むべき方向へと次のステップを踏み出しました。
つまるところSignalをなくすことは可能でした。なぜなら、Elmは並行性を明示的に強調する方向へと動き出したからです。この萌芽は論文中で明らかですが、実際に車輪が回りだしたのはElmにタスクが実装されたバージョン0.15からです。0.15のリリースではまた、スケジューラーも導入されました。Elmのバージョン0.17においては、このスケジューラーが大いに改善されました。ErlangやElixirで使われているBEAM VMから得た示唆をベースにしています。Process
モジュールのドキュメントにおいて、どのように動くのかや将来的な動きについて詳細を読むことができます。スケジューラーはまた、effect managersの基盤でもあります。effect managersはそもそもsubscriptionを可能にするものでもあります。このあたりのドキュメントをもっと充実させたいのですが、幸いあなたはこれらのことを知ることなくElmのエキスパートになることができます。私の論文のConcurrent FRPの項で述べたように、ゴールは並行性の旨みをカンタンに手にすることです。
関数型リアクティブプログラミングに関するElm?いえ。そのような日々は終わりました。Elmは並行性を真剣に考えている単なる関数型言語です。ユーザの視点から見ればElmは非常にフレンドリーな関数型言語です!