リアクティブプログラミング(reactive programming)とは?
最近、リアクティブプログラミングという言葉を目にすることが多くなりました。
リアクティブプログラミングは、CPUのマルチコア化やクラウドの活用が進む中で、 非同期通信に基づいたアプリケーションの設計に適しているため、 これからのソフトウェア開発における重要な技術として注目されています。
まず、以下の擬似コードを見てみましょう。
a = 1
b = 2 * a
a = 2
print b
プログラマに対して無前提にこのコードの出力結果を訊けば「2」と答えるかと思います。
しかし、リアクティブプログラミングの観点でみると「4」が出力されるべき、という答えになります。
というのは、リアクティブプログラミングの観点では、2行目の「b = 2 * a」というコードは 「bをaの2倍として定義する」という意味で解釈されるからです。
つまり、aとbの関係性を定義した後は、「aへの代入」というeventへのリアクションとして 「bの再計算」を常にバックグラウンドで行う、このようなパラダイムのことをリアクティブプログラミングと呼びます。
リアクティブプログラミングのメリット
これまでの命令型プログラミングでは、特に非同期の並行処理において様々な問題がありました。
例えば、
- コードが複雑化する
- 命令の実行順序を管理することができない
- 幾重にもネストされたコールバック(いわゆるコールバック地獄)
などです。
リアクティブプログラミングを活用すると、シンプルなコードで上記を記述し、アプリケーションの動作を管理することが可能になります。
リアクティブプログラミングの技法的な特徴
behaviorとeventというパラダイム
リアクティブプログラミングでは、時間の関数として与えられる「behavior」と、 時間と値の組である「event」で処理を記述していきます。
behaviorは時間を通じて変化する値であり、eventはある時間においてbehaviorに働きかけるもの、と考えることができます。
例えばブランコの動きを制御するプログラムを書いた時、behaviorとして「ブランコの位置」「ブランコの速度」というものが考えられ、これらは相互に関係します。
またeventとして「ブランコを押す(実装の一例として、ブランコの速度に定数を足す)」というものを考える事ができます。
他にも様々なeventを定義する事で、ブランコの多様な動きを制御したり、複数のブランコを組み合わせたり、別の概念と関連させたリアクティブアプリケーションを作ることができます。
上記の例では、a、bという変数がそれぞれbehaviorに当たります。
「b = 2 * a」という式がbehaviorどうしの関係性を記述し、ある時刻に起きた「a = 2」というeventがaのみならずbも変化させるという実装を示唆しています。
GoFのオブザーバーパターン(Observer pattern)
後述する各種プログラミング言語のリアクティブプログラミングのための拡張である Rx ライブラリは、その根幹にオブザーバーパターンという考え方を持っています。
オブザーバーパターンは1995年にGoF(Gang of Four)によって提案された23のデザインパターンの一つであり、プログラムのインタフェースとしては古典的なものです。
Subject(監視対象)とObserver(観察者)からなるパラダイムで、利用シーンとしては、GUIの設計においてデータベースの変更を検知して表示を自動更新したい場合などが代表的です。
実装の概略は以下の通りです:
- 監視対象のオブジェクトに観察者を登録する(このことから、観察者は購読者(subscriber)とも呼ばれる)
- 監視対象のデータベースに変更があった際にメソッドが呼び出され、すべての観察者に変更が通知される
- 監視対象、観察者はお互いの内部設計を知らなくてもよい
GUIの例においては、GUIクラスが「観測者」、データ処理クラスが「監視対象」ということになります。
オブザーバーパターンを用いることの利点は、観察者の実装に変更が加えられたとしても、監視対象の実装を変更しなくても良いという点です。
MVC(Model View Controller)モデルにおいてModelの設計がViewの設計に依存するというのはありがちなことです。
オブザーバーパターンでは通知のメソッドさえ共有されていれば良く、一方の変更によって他方を設計し直す必要がありません。
そのため、拡張可能性の高いアプリケーションが開発出来ることが知られています。
以下で説明するRxライブラリにおいて、オブザーバーパターンに準拠したクラスが実装されています。
Rx(Reactive Extensions)
Rx(Reactive Extensions)とは各言語においてリアクティブプログラミングを実現させる拡張機能を指します。
2009年からMicrosoft DevLabsにおいて進行していたプロジェクトであり、2011年に製品化され様々な分野で非同期処理が可能となりました。
C#・LINQ(Language Integrated Query)におけるRx
LINQはC# 3.0から追加された機能であり、元々はC#に対してSQLライクなクエリやRDB操作を可能にしたものでした。
そこに非同期処理やイベント処理を可能にする機能拡張が行われました。
LINQ to Objectsという従来の機能に対比させて、LINQにおけるRxをLINQ to Eventsと呼ぶこともあります。
Rxの記法はLINQの記法に似ていますので、前提知識としてLINQを知っていると習得に有利です。
各言語のRxライブラリ
2009年にマイクロソフトが提供開始したのRx.NETを皮切りに、RxJava、RxJS、RxSwiftなど様々な言語向けにRxライブラリが開発されてきました。
またマイクロソフト外のチームが開発したRxライブラリもあり、UnityのRxであるUniRxなどが挙げられます。
参考サイト | 説明 |
---|---|
Reactive.net | RxJS、Rx.NETなどのGithubページ |
ReactiveX | RxSwift、RxJavaなどのGithubページ |
UniRx | UniRxのGithubページ |
FRP(Functional Reactive Programming)
リアクティブプログラミングの研究を早くから進めていたのがHaskellユーザーで、Conal Elliotによる1997年の論文が有名です。 (参考: http://conal.net/papers/icfp97/)。 Haskellのような関数型言語で実現されるリアクティブプログラミングをFRP(functional reactive programming, 関数型リアクティブプログラミング)と呼びます。 上記の論文に準拠する「Fran」というHaskellで記述されたシステムのチュートリアルは、リアクティブプログラミングの事始めとして多くのプログラマに親しまれています。(参考: http://conal.net/fran/tutorial.htm) このページでは複数の男の子の顔面がダンスをするという滑稽なアニメーションが公開されており、従来のプログラムに比べてFRPでは非常に簡潔に記述出来る事を述べています。
HaskellでFRPを実装するためのライブラリ集
ライブラリ | 解説 |
---|---|
Reactive | Franに似た古典的FRPライブラリ |
Yampa | Signal Functionを用いるArrowised FRP。Yale Haskell Groupが開発 |
Grapefruit | オブザーバーパターンがPush式のFRP |
関連記事
- 2018/07/18 全文検索を自社サイト・社内サーバーに構築したいクライアントのための留意点 システム開発における「全文検索」の実装方式・コスト・性能に関して、クライアント企業の方にも腹落ち頂けるようまとめました。grep型と索引型の違いに関する平易な解説を記載しているので、これらをクライアントに解説されたい開発者にもオススメです。
- 2018/02/01 利益管理のためのデータ可視化 技術者にできる事は何か? データ可視化は科学技術分野において発祥した技術であり、与えられたデータから自動的に「見やすい図示」を出力するアルゴリズムを指します。データを見やすくし、ビジネスの意思決定に活用するという観点から手法を紹介し、R言語によるデモを行います。
- 2017/12/28 機械学習・統計学・最適化の違いについてまとめてみた 「機械学習」という手法は、システム開発の現場で用いられる事例が急増しています。一方、「統計学」という分野も機械学習と同様にデータを扱い、やはり多数の事例があります。本記事は「機械学習と統計学の違い」について整理することを試みます。
- 2017/12/04 システムによる最適化を通じて、開発者がめざすもの 〜エレベーターの制御システムを例に〜 システム開発においてお客様の要望に応えようとするとき、いろいろなところで「システムによる最適化」を含む開発アイデアを発想します。この記事では、最適化を成り立たせる「目的関数」と「制約式」という思考法を紹介します。
- 2017/06/30 Chainerを使ってMarkov chain(マルコフ連鎖)を書いてみる 本記事は、Python上で動作するニューラルネットワークのライブラリ「Chainer」を使ってマルコフ連鎖を実装、様々な実験を行うものです。本来関係のない両者を結びつけることでどんなメリットが得られるのでしょうか?