Functional Reactive Programming on Web

lab

February 1, 2016    ]

Webフロントエンドでリアクティブプログラミング

最近インタラクティブで複雑なUIを持つアプリをWebで作る機会が増えてきました。Webサイトもどんどんとリッチ化し、アプリのようなUIを求められるようになってきました。それをなんとか実現するために jQueryプラグインを山ほど詰め込み、ライブラリの競合解決、複数コンポーネント間の連携、UIタイミングの調整、などなどゴリゴリつくるのにも限界を感じてきますよね。

Backbone や AngularJS、Knockout、Sencha、etc、、と大規模アプリケーションを作るためのフレームワークやライブラリが百花繚乱です。これらを利用することで問題の一部は解決します。が、どれもまだ完璧とまではいきません。

もっと根本的に UIインタラクションを簡潔に記述できないものか。

それを解決するヒントが関数型言語、特に Functional reactive programming にあるかもしれない、と興味を持っています。そこでGWの自由研究として、最近のWebフロントエンドでのリアクティブプログラミングについて調べてみました。

関数型プログラミング


関数
関数型言語は格別新しい言語というわけでは全くありません。古くは 1970年代から Lisp や Schema が一部ではよく使われていました。しかしここ数年、様々な開発の現場でも使われる機会が増えています。

Twitter や LinkedIn で Scala が採用されていることは有名です。Facebook や Github の一部では Erlang が動き、Haskell は Gree や金融取引などのシステムで使われています。エアバスは OCaml で飛んでいるともいわれます。

また、Java8 では遂にラムダ式のサポートより Stream API で宣言的にリスト処理をかけるようになりました。これによって既存の Java システムでも関数型アプローチの採用が進むのではないでしょうか。

関数型言語の特徴は、言語や実装により多少差異はありますが、概ね次のようなことが言えます。

  • 不変性(Immutability)
  • 参照透過性
  • 高階関数
  • 遅延評価
  • 型安全
  • 宣言的
  • 分散処理

これらの詳細については、今回は省略します。まぁ、色々とメリットがあると思ってください。詳しく知りたい方は「なぜ関数プログラミングは重要か」を読んでみて下さい。

JavaScript で関数型プログラミング


上で述べた事例は主にバックエンド、サーバーサイドでの利用が中心でした。当然、Webのフロントエンドでも関数型言語の恩恵を受けたいですよね。

しかしWebフロントエンドで使われる言語は、(ほぼ)JavaScript 一択です。JavaScript の言語仕様で関数はファーストクラスオブジェクトになっていますが、関数型言語としての側面はあまり強くありません。そこで、JavaScript で関数型パラダイムを活用するために、大きく分けて二つのアプローチがあります。

functionalJS
1つ目は、JavaScript で書かれたライブラリを使用し、関数型言語的に記述できるようにする方法です。代表的なものに Underscore.js があります。これは、配列やオブジェクトの操作を関数的に簡潔に書くためのユーティリティ集ともいえる軽量ライブラリです。MVCフレームワークとして人気のある Backbone.js の内部で使われていることでも有名です。特に underscore-contrib を一緒に使うとさらに関数型として活きてきます。

フロントエンドライブラリの代名詞ともなった jQuery も実は関数型です。jQuery Deferred が導入されてメソッドチェーンで宣言的に遅延評価を記述できるようになり、ますます関数型的ぽくなりましたね。また、データビジュアライゼーションの雄 D3.js も関数型アプローチでデータを扱うことで、複雑な表現を簡潔な記述で表すことを可能にしています。

JavaScript で関数型パラダイムを使用する 2つめのアプローチは、別の言語で記述したソースをコンパイルして JavaScript に変換する、AltJSと呼ばれる方法です。様々な AltJS がありますが、関数型といえば ClojureScript です。おおまかにいって、JVM で動く Lisp と言われる Clojure をWebで動くようにしたものが ClojureScript といっていいでしょう。また、OCaml で作られた Haxe も、クラスベースでありながら関数型の特徴も持つとも言われます。

AltJS のメリットは、JavaScript の言語仕様に縛られずに簡潔に関数型プログラムを記述できることです。一方、独自言語の習得のための学習コストは上がることや、コンパイルする手間がかかるというデメリットもあります。

関数型ライブラリ、関数型Alt JS、どちらもそれぞれメリット・デメリットがありますので、プロジェクトの性質やメンバーなどについて使い分けるとよいのではないでしょうか。

リアクティブプログラミング


JavaScript でも関数型アプローチが使えることがわかりました。これらを活用することよって、宣言的に簡潔に記述可能になりそうです。しかし、冒頭でも述べたような、よりリッチでインタラクティブなものを作るのに関数型は適しているのでしょうか。半分使えると言えるし、半分はそうでもないとも言えます。

ロジック部分は関数型で作るメリットは大きいです。しかし、ユーザーとのインタラクションや、時間経過によるアクションのようなシステム外部とのやりとりは、純粋関数型指向では扱いが難しくなります。

そのような問題を解決する方法として (Functional) Reactive Programming という考え方があります。

Reactive Programming というと、Functional Reactive Programming のことを指すことが多いですが、厳密には異なります。Reactive Programming はデータフローから発展し、モデルデータの伝搬をどう実現するかが主題のプログラミングパラダイムです。リアクティブ = 反応的のように、あるイベントに反応し自動的に対応する、というのがリアクティブの考え方です。

良く例に出されるのが、エクセルのセル計算です。セルの値を変更すると、そのセルを参照している計算式も自動的に変更されますよね。これがリアクティブであるといっています。

もっとプログラマ的に分かりやすくと言うとデータバインディングですね。Knockout や AngularJS の宣言的手法による双方向データバインディング(Backbone では stickit)は、リアクティブであるといえます。

リアクティブとはどういうことかについて宣言した、The Reactive Manifesto1 が昨年出されました。ここでいうリアクティブはかなり広義の定義をしていて、リアクティブプログラミング はその一部分といった感じでしょうか。いずれにせよ、リアクティブという考え方が今後一つのキーワードになってきそうです。

その Reactive Programming にさらに関数型の特徴を加えたものが Functional Reactive Programming (FRP) です。元々データフローと関数型プログラミングは相性が良く、データの流れを宣言的に簡潔に記述できます。

FRP は Haskell のコミュニティを中心に発展し、Haskell Wiki に概念がまとめられています。最初のアイディアは1998年に Conal Elliot と Paul Hudak により Functional Reactive Animation として発表され、それを受けて Haskell のライブラリや実装が沢山作られました。このペーパーを書いた Conal Elliot が FRP について述べたものが StackOverFlow にあります。

FRPとは何でしょうか?

  • 時間をかけてダイナミックに変化する値は、ファーストクラスの値です。それらを関数の in/out にして組み合わせることが出来ます。これを Behavior と呼んでいます。
  • Behavior は、静的な動作や時計のような時間といったいくつかのプリミティブなものから構築した後、順番または並列に接続にします。n個の Behavior は、連続した時間のような離散的な n個の関数によって合成されます。
  • その 離散的現象を表すために 有限または無限に出現するストリームを持つ Event があります。Event は時間と値のペアです。

(意訳: What is (functional) reactive programming?)


つまり、FRP のポイントは、入力のような時間的に変化する値を Behavior という関数で表し、離散的な値を時間のペアをEvent Streamとして扱うことで、刻々と変化する値を宣言的に表す、ということです。(これだけだと絶対なんのことか意味が分からないと思うので、後述する Bacon.js のスライドを見るとよく分かります。)

この回答が珠玉なのは、実は FRP の説明では無くその後の

どこでこの原則を手に入れたかだって?
私はソフトウェアを設計するとき、いつも同じ質問をする。

「それは何を意味するのか?」


にあったりするのですが、それはまた別の機会に。

日本語情報はについては以下のものが参考になりました。


JavaScript でリアクティブプログラミング


リアクティブプログラミングのパラダイムは、いろんな言語で展開されています。もちろん、JavaScriptの実装も沢山あります。ここではその幾つかを紹介します。

RxJS

RxJS

もともと Reactive Extensions (Rx) という .NETのフレームワークがありました。

Rxは、2009年11月18日に、マイクロソフトの開発部門およびMicrosoft Researchの実験的なプロジェクトを公開するポータル・サイト「Microsoft DevLabs」にてページが開設され、その後、1年半に渡り細かく試験的なリリースが続けられてきた。

(引用: Reactive Extensionsの概要と利用方法)


これを JavaScript へ移植したものが RxJS です。このプロジェクトも Microsoft Open Technologies で開発がサポートされています。2010年頃から作られていて現在も活発に開発されています。単独の JavaScript ライブラリとして動くため、コンパイルなどは必要ありません。

RxJS = Observables + LINQ + Schedulers と表されています。

Observable で非同期のデータストリームを表し、そのコレクションをLINQで関数型的に扱い、Scheduler で非同期に同時実行する、といったものです。LINQ というのは .NET 環境での統合言語クエリとして作られた関数型的なコレクションライブラリのようなもので、他のプラットフォームにも移植されています。

歴史があるので、わりと安定しているイメージがあります。JavaScript の FRPライブラリとしては老舗の部類です。

Bacon.js

Baconjs

RxJS からインスパイアされてできた後発の FRP ライブラリです。コンセプトはほとんど RxJS と同じですが、後発の分 色々と洗練されている感じがあります。個人的にはこちらのほうが馴染みます。

RxJS と何が違うのか、公式に説明があります。

Bacon.jsはRxJsに触発され、同様のコンセプトを持っています。設計上の主な違いは、Observable に EventStream と Property の2種類があり、明確に意味が定義されていることです。RxJs の Observable はしっかりと意味論を結び付けません。例えば、RxJsでは、同じObservableインターフェイスを公開していても、「ホット」と「コールド」のような異なる挙動もあります。
また、Bacon.jsは完全にオープンソースであり、(おそらく)より良いドキュメントを持っています。

(意訳: What's the difference to RxJs?)


github上でもこちらのほうが人気があるようですね。Readmeの日本語訳もあります。
開発者の一人である @philip_roberts による解説スライドが非常に分かりやすいです。FRP の解説としても役に立ちます。

React

Ract

Facebook が作成したリアクティブフレームワークです。Instagram でも使われているとして一時話題になりました。Virtual Dom や データバインディングが W3Cに提案されている Web Components と似ていると良く比較されます。

方向性や実現方法は面白いのですが、、一部では筋悪いとあまり評判がよろしくないようです2。JavaScriptの文中に XMLリテラルを記述し、コンパイルするとJSのコードになる JSX というもので記述するのが標準化されそうに無い独自記法なところがなんともですね。昔 E4X3 とかあったのを思い出します。ちなみに、DeNA の JSX とは関係ありません。

Ractive.js

Ractive

こちらはデータバインディングに特化した感じで、どちらかというとリッチなテンプレートエンジンといった雰囲気でしょうか。Functional な感じはあまりありません。双方向データバインディングが簡単に行え、AngularJS や KnockoutJS よりもコンパクトでシンプルだそうです。Behavior や EventStream はないので、FRPとはいえなそうです。

分かりやすいためか、上記の Bacon.js よりも スターが多いのが個人的には解せませんが、そこそこ流行っているようです。

こちら Ractive.js入門 に日本語の解説があります。

elm

elm

長々と解説してきましたが、お待たせしました。ようやく私的本命の登場です。

Elmは、HTML/CSS/JavaScriptにコンパイルする関数型言語です。関数型リアクティブプログラミング用に設計されたエルムは、簡単に高度なインタラクティブアプリケーションを作成することができます。

(意訳: http://elm-lang.org/)


AltJSの一つと言って良いのか微妙ですが、Elm言語で記述したものを専用の elm-server で動かす Webアプリケーションプラットフォームです。Elm言語とは、純粋関数型言語である Haskell をベースに、Webフロントエンド用に拡張したものです。

何が良いかというと、純粋関数型言語なので最初の方で述べた関数型言語のメリットが100%活かせます。むりやりJSを関数型っぽくしたのとは訳が違います。それでいてリアクティブ要素が組み込まれているため、インタラクティブな制御も楽々です。簡潔!短い!美しい!バグが(少)無い!

サイトにあるサンプルでコードが確認できますが、非常に短いコードでシンプルに記述できることが分かります。また、定番の TodoMVC を elm で書いてみた TodoFRP をみると、こちらも非常に短いコードでロジックが記述されています。

個人的に非常に興味があり、今すぐにでも使ってみたいところですが、少し問題があります。HTML/CSS も全て elm で生成するので、レイアウトが非常に面倒くさい!!

一応 elm --only-js を使えば、JSだけビルドされるため既存HTMLに組み込むこともできますが、基本は elm言語でレイアウトもするようです。

プロダクション環境で動かすときにこれで出力し、本番用サーバーで動かすのでしょうね。さすがに elm-server でプロダクションサーバーとして運用するのは色々怖すぎます。

しかし、elmに関する日本語情報が少なすぎます。こちらくらいしか見当たりません。非常に参考になりました。
Elmで始めるFunctional Reactive Programming

みなさん、elm やりましょう!そしてBlog書いてください(切実)

まとめ


関数型プログラミングの超概要から、最近のフロントエンドでの関数型言語、Functional Reactive Programmingと、JavaScriptでの利用についてまで駆け足でお伝えしました。今年こそは、そろそろリアクティブがフロントエンドでもくるんじゃないかなぁ、と思っています。

私もまだまだ関数型言語の初心者ですが、新しいことに挑戦するのはワクワクしますね!

ediplex ではそんな新しい事に挑戦するエンジニアを募集しています。
ぜひ一緒に楽しく挑戦しましょう!

  1. 日本語訳: The Reactive Manifesto 日本語訳 []
  2. Facebookの React JavaScript ユーザーインターフェースライブラリは、様々な批判を受けている []
  3. E4Xは廃止されてしまいました。 []