search
LoginSignup
12

More than 5 years have passed since last update.

posted at

updated at

Functional Reactive ProgrammingとElm

この記事は Elm Advent Calendar 2016 11日目の記事です。

まえがき

ElmはかつてFunctional Reactive Programmingの本命と言われていました。しかし、ElmはFRPと袂を分かってしまいます。A Farewell to FRP という記事にその内容が記されています。
日本語訳もこちらに出ているので、ぜひ目を通してみてください。

しかし、Elm を学んで幾つかアプリを作ってみるという経験を通して、 Elm(Elmアーキテクチャ)の本質はFRPであると強く思うようになりました。

Functional Reactive Programming とは

FRPには決定的な説明はなく、様々な形でその概念を説明しようという試みがなされています。例えば、Wikipediaには

Functional reactive programming (FRP) is a programming paradigm for reactive programming (asynchronous data-flow programming) using the building blocks of functional programming (e.g. map, reduce, filter)

とあり、Haskell Wikiには

Functional Reactive Programming (FRP) integrates time flow and compositional events into functional programming.

という説明があります。

この2つの説明に共通しているのは、「FRPとは非同期的なデータストリームを扱うプログラミングパラダイムである」という点ではないかと思われます。

では、その「データストリーム」とは一体何なのでしょうか。以下、非同期的なデータストリームについて触れた上で、その次にElmアーキテクチャとの関連を考えてみたいと思います。

非同期的なデータストリーム

FRPという概念が最初に提唱されたのは1997年のFunctional Reactive Animationという論文です。ユーザーからのインタラクティブな操作を関数として操作するため、BehaviorとEventという第一級の値が考えられました。その定義はだいたい次のようになります。

$Time \equiv \left\{ t \in R | t > 0 \right\}$

$Behavior \ a \equiv Time \rightarrow a$

$Event \ a \equiv List(Time \times a)$

Timeとは時間を表し、Behaviorは時間の関数、そしてEventは時間とペアになった無限リスト(すなわちストリーム)と考えられます。これから、非同期的なデータストリームとは、時間と値がペアになった無限リストであるということができます。

Elmアーキテクチャ

Elmアーキテクチャはリアクティブなアプリケーションを作成する上で、我々にとって使いやすいパラダイムを提示してくれました。
FRPを全面に出していた以前よりもとっつきやすく、それぞれの要素を意識してプログラミングすれば良いので、より書きやすくなったのではないかと思います。
しかし、ElmアーキテクチャはFRPを知ると、よりアーキテクチャ自体の理解が進むのではないのかと思います。非同期的なデータフロープログラミングであるということを念頭に置くだけでも、Elmアーキテクチャのそれぞれの要素の相互関係がわかりやすくなるのではないでしょうか。

まず簡単にElmアーキテクチャについて解説します。
次に、ElmアーキテクチャとFRPを結びつけて捉えてみます。Elmアーキテクチャを構成するのに重要なModelUpdateSubscription を中心に考察します。

Elmアーキテクチャの簡単な説明

Messages

アプリケーションを操作させるためのトリガーとなるもので、 Updateでハンドリングします。

Model

Modelはアプリケーションの状態を表しており、その中でもinitは初期状態を表しています。

Update

Messagesを受け取って新しいModelを返します。
場合によっては新しいCommandを発行します。

Command

外に出す命令、コマンドのことで、DBの検索やTaskを実行します。

View

HTMLとして状態を表現します。

Subscription

マウスイベント、キーボードイベントや時間などの外部イベントをリッスンさせるための機構です。

Main

アプリケーションを実行します。

ElmアーキテクチャとFRP

ModelUpdate

Elmアーキテクチャでいうところの Model は、FRPとして解釈するとデータストリームに相当します。Elmの公式チュートリアルには

Model — the state of your application

とあります。Elm アーキテクチャでは Model を状態と呼んでいますが、これは初心者であったときの私にとってはややわかりづらい説明でした。なぜなら、状態があるならそれはミュータブルな世界があって、それを破壊的に変更できる、という先入観があったからです。しかし、Elm アーキテクチャの ModelUpdate のシグネチャーを見てみましょう。

model : Model

Model については説明は不要だと思います。

update : Msg -> Model -> Model

Update については、メッセージと Model を順番に受け取って、新しい Model を返すというように読むことができます。したがって、状態を更新する、という説明はややわかりづらいのではないかと思われます。ElmアーキテクチャをFRPの延長として捉えるのであれば、UpdateModel というデータストリームをハンドリングし、新しい Model を返す関数と捉えるのがいいのではないでしょうか。

Subscription

さらに、データストリームとして捉えるという方法は、Subscription の挙動を理解する上で役に立つのではないでしょうか。
シグネチャーを見てみましょう。

subscriptions : Model -> Sub Msg

Model を受け取り、Sub Msg を返します。クリックイベントやマウスイベントなどの外部イベントは、そもそも Model には組み込まれていません。したがって、Subscription無からストリームを作っていると見て取れます。そして、それを Update でハンドリングし、新しいストリームを返すと考えられます。

View

View のシグネチャーを見てみましょう。

view : Model -> Html Msg

View はストリームの任意の要素をレンダリングする存在そして捉えられます。無限リストを受け取って、ある時刻 $t$ の要素をHTMLに変換し我々に提示します。

Elmアーキテクチャにおけるデータフロー

以上の説明を簡単な図にすると、次のようになるかと思います。無限リストの中の一つのセルにおけるデータの流れを図にしてみました。以下のような図が無限に連なっていると考えてください。
ModelがUpdateによって次々と更新され、途中SubscriptionをUpdateが受け取ってさらに新しいModelを構築しながら、それが最終的にViewによってレンダリングされます。
https://gyazo.com/57bcbd6e4b1728d7ca726e52620a1595

参考

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
12