FRPとVirtual DOM、状態について。

# FRPとVirtual DOM、状態について。

今回は、Elmを通して、FRPに対する個人的な理解、そしてVirtual DOMがFRPに合っているということを述べていきます。

# FRP 

## 関数プログラミングはどのように「状態」を扱うのか?

「Functional Reactive Programming」とあるように、FRPは関数プログラミングのパラダイムの技法だと思います。なので、関数プログラミングについてまず、「**状態**」について考えてみたいと思います。

### 状態とは何か?

まず、状態とは何でしょうか? [CTMCP](http://www.amazon.co.jp/dp/4798113468/ref=cm_sw_r_tw_dp_FI3Mub1PTP92Y)によると、

> 状態(state)とは、必要とされる計算の途中結果を含む、値の時系列である

とあります。関数プログラミングのような**宣言的**なプログラミングは、そしてこの書籍では**暗黙的状態**を扱い、オブジェクト指向のような**命令的**なプログラミングは**明示的状態**を扱うと述べています。

### 値と、オブジェクトと、「状態」

関数プログラミングは、「**値**」を扱います。ここでの「値」というのは、それ自身は状態を持ちません。つまり、値は、状態を変更することができないものです。そして、**オブジェクト**は内部状態を持ち可変です。つまり、「**不変な値**」をそのまま「**値**」として、「**オブジェクト**」を「**可変な状態を持つ値**」としています。

関数プログラミングは、**値**しか扱うことができません。では、どうやって、状態を扱うのでしょうか?ここでは、まず命令的なプログラミングを、関数プログラミングに置き変えながら考察していきたいと思います。

さて、まず、**命令的**なプログラミングで、状態を考えてみましょう。たとえば、以下のようなコードを考えましょう。

```js
function Person(name, age){
  this.person = name;
  this.age = age;
}

Person.prototype.older = function(){
  this.age++;
}

var nobkz = Person("nobkz", 20);
nobkz.older(); // age : 21
nobkz.older(); // age : 22
```

さて、このコードは、ageが状態変数であり、olderを呼ぶ回数だけ、ageがインクリメントされます。つまり、ageが更新され、**再代入**されるということになります。つまり、Person **オブジェクト**が**明示的に状態**を持ち、olderによって、状態を変更しているということです。

さて、関数は値を更新することができません。なので、どのように状態を扱うのでしょうか? **状態が更新するとき、更新後の値を別の値にすれば良いのです**。つまり、**遷移前の値と、遷移後の値を別々にするということです**。コードにするとこういうことになります。

```js
function newPerson(name, age){
  return {name:name,age:age};
}

function older(person){
  return {name:person.name, age:person.age};
}

var nobkz = newPerson(name,age);
var nobkz1 = older(nobkz);
var nobkz2 = older(nobkz1);
```

このコードは、**暗黙的に状態**を扱っています。というのも、ここで、nobkzとnobkz1、nobkz2の値がありますが、コード上では単に違う値としか扱えません。プログラマが、nobkz,nobkz1,nobkz2が**状態として扱う**と解釈しているにしかすぎません。

ここで、重要なのは、状態遷移の関数の書き方です。**状態遷移の関数は、古い状態を受けとり、新しい値を作ってそれを、新しい状態として返す**ということをやっています。つまり、宣言的な書き方と、命令的な状態の記述は、**状態の変更をそのまま記述する**か、**古い状態から、新しい状態を作る**の違いがあります。

## FRP(Functional Reactive Programming)とは?

### 時間変化の型

さて、Functional Reactive Programmingは、何か?と言われれば、**時間変化の型があって、その型の値を結合しながら、プログラミングしていく**ということだと解釈しています。

たとえば、[Elm](http://elm-lang.org/) などをは、Signalという型が時間変化の型で、その値を結合しながらプログラミングします。Signalは一つの型引数を持ち、様々なデータ型を内包することができます。

### Signalと関数を結合する

Signal例として、elmでは、マウスをクリックしたときは、Mouse.clicksというSignalの型の値を使います。

```
Mouse.clicks : Signal ()
```

さて、Elmでは、map関数などによって、Signalの値を関数を組み合わせて行きます。
たとえば、次の関数を結合しましょう。

```
one : () -> 1
one () = 1
```

関数oneは、()を取り、1を返すだけです。さて、これと、Mouse.clicksを結合させたいのですが、残念ながら型が合いません。

```hs
import Mouse

oneClicks = one Mouse.clicks -- 型が合いません!

one : () -> Int
one () = 1
```

上記のコードはこのような型がマッチしないという、エラーを出すでしょう。

```
Type mismatch between the following types on line 3, column 17 to 29:

       Signal.Signal ()

       ()
```

では、どうすれば良いかというと、Signal.map関数を使い、one関数をSignalの型に**持ち上げ**れば良いのです。

```
Signal.map : (a -> result) -> Signal a -> Signal result

signalOne : Signal () -> Signal Int
signalOne = map one
```

そして、それを、Mouse.clicksに適用すれば良いのです。

```hs
import Mouse
import Signal (Signal, map)

oneClicks = signalOne Mouse.clicks

signalOne : Signal () -> Signal Int
signalOne = map one

one : () -> Int
one () = 1
```

### Signalは動的に生成する値

Signalという型は、動的に生成する値です。先程のMouse.clicksは、()という値を、クリックしたときに**動的に生成している**わけです。そして、動的に生成されて、map関数などで、結合された関数が呼びだされます。

それは次のコードで確かめることができます。


```hs
import Mouse
import Signal (..)
import Text (asText)
import Debug (log)


main = asText <~ map (\x -> log "clicked" x) Mouse.clicks
````

とすると、こんな感じで、ログが表示されるはずです。

![スクリーンショット 2014-12-25 16.22.20.png](https://qiita-image-store.s3.amazonaws.com/0/31381/e7e43878-09c8-2511-2e7f-4ab4a872c198.png)



さて、このコードは、Mouse.clicksと、ラムダ(\x -> log "clicked" x)が結合しており、クリックすると、Mouse.clicksの**Signalの中身の値が生成**され、そして、結合している、ラムダ式が呼び出されます。

注意したいのが、あくまでも、Signalの**中身の値**が動的に生成されるというわけです。つまり、Signalの値自体は、最初から生成され、クリックしてもなにも起こりません。

```hs
import Mouse
import Signal (..)
import Text (asText)
import Debug (log)

main = asText <~ log "clicked" Mouse.clicks -- クリックしても、何も起こらない!
```

### 動的に末尾に追加されるストリーム

さて、Signal Value自体を見てみますと、**状態を持つ、可変な値**のように見えます。たしかに、たとえば、elmのMouse.isDownは、そのように見えるかもしれません。

```hs
main = asText <~ Mouse.isDown 
-- マウスを押したとき-> True
--- マウスを話したとき -> False
```

Mouse.isDownは、Signalというオブジェクトとして、内部状態を持っており、Trueと、Falseを更新しているように見えます。

先に、関数型は、**可変な値を扱うことができない**と言いました。あれ?何か矛盾してる気がしますね。

それはSignalを**動的に末尾に追加されるストリーム**として考えれば良いと思います。良い代えれば、**動的に伸びる無限リスト**とみるということです。

たとえば、普通のリストの計算を考えてみましょう。

```hs
List.map not [True,False,True] --  [False, True, False]
```

さて、この計算は、Bool型のリストをnotでmapします。これと似たような、Signalのコードを見てみましょう。

```hs
Signal.map not Mouse.isDown
```

さて、これは、次のように考えると、スッキリするでしょう。

```hs
Signal.map not [True, False, True, False, True ...... 
--クリックする度に伸びていく

-- 入力値 -> [True, False, True, False ....
-- 出力値 -> [False, True, False, True....
```

さて、更にListのfoldの計算を考えてみましょう。たとえば、リストの長さは次にのようになりますが、

```hs
List.foldl (\x y -> y + 1) 0 [(),(),(),(),(),()] -- -> 5
```

これと、似たようなことをSignalにすると、Signalには、foldpという関数があり、

```hs
Signal.foldp (\x y -> y + 1) 0 Mouse.clicks
```

これは次のように、なり、

```hs
Signal.foldp (\x y -> y + 1) 0 [(), (), (), (), (), .....
--クリックする度に伸びていく

```

とすればクリックした回数をカウントすることもできます。

つまり、Signalは、無限に追加されるリストのようなものであって、追加されたときに、結合した関数を呼び出すものだと言えます。


## FRPとVirtual DOM


さて、関数プログラミングでは、先程も良いました通り、状態管理は、**遷移前の値と、遷移後の値を別々なものとして扱い、古い状態から、新しい状態を作る**ことによって、状態を表現すると言いました。

とすれば、**何かイベントがある毎に、新しい値が生成されます**。それを、そのまま、新しい値からDOMを生成するとなれば、イベント毎に毎回新しいDOMが生成され、非常に非効率です。

なので、**古い状態の仮想DOMと新しい状態の仮想DOMの差分**を取り更新するというような、最適化はFRPのプログラムの効率化をサポートするでしょう。


つまり、ElmのSignalのような仕組みによって、**イベント毎に新しいGUIの状態が生成され、Virtual DOMによって、古い状態と新しい状態を比較して、状態を反映していく**と言う形で、関数プログラミングをしながらGUIを構築していくということが、FRPによるプログラミングになるでしょう。