Elm Architecture の Model-View-Updateについて

[Elm開発環境について](https://qiita.com/sand/items/9afaef65c6f1ebf453da "Elm開発環境について")
[Elm Architecture の Model-View-Updateについて](https://qiita.com/sand/items/d9830b4226710a969488 "Elm Architecture の Model-View-Updateについて")


**(2019/01/30 修正) 0.19対応　toString を String.fromInt で置き換えました。**



　Elmは純粋な関数型言語であり、Webアプリ専用の言語でもあります。両者は相反するように思えますが、HaskellでもYesodを使ったWebアプリを作成できますので．．．。要するにHaskellは純粋でないダーティな部分はIOモナドで隔離します。同じようにElmではElm Runtimeにダーティな部分を任せて、自身の純粋さを保つようにしているようです。

　ElmはWebアプリのArchitecture をModel-View-Updateという形でパターン化しています。前回取り上げたソースコードで説明していきます。公式サイトにあるボタン表示のプログラムを微修正したものです。
https://guide.elm-lang.org/install.html

# １．View　Only

　その前に以下の簡略化されたソースコードを見てください。これは35という数字をブラウザに表示してくれるプログラムです。

```elm:MyButtons.elm（シンプル版）
module MyButtons exposing (..)

import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)

main = view "no model"
view model =
    div [] [ text (String.fromInt 35) ]
```

　MyButtons.elmはコンパイルされてelm.jsになります。以下のようにindex.htmlでelm.jsは読み込まれます。そしてElm.MyButtons.embed()でMyButtons moduleのmain関数がこのアプリのエントリーポイントとして使われるようになります。つまり関数 view "no model" が実行されます。

```html:index.htmlのコア部分
        <div id="elm-area"></div>
        <script src="elm.js"></script>
        <script>
            Elm.MyButtons.embed(document.getElementById("elm-area"));
        </script>
```

　view関数は引数としてmodelを取りますが、右辺では使われていないのでダミーで十分です。結果的にHTML(DOM)を生成します。div [] [ text (String.fromInt 35) ] はdivタグを表します。最初のリスト[]は属性のリストで、2番目のリスト[ text (String.fromInt 35) ]　は子要素のリストです。つまり ＜div＞35＜/div＞となり、index.htmlの中で以下のように展開されます。

```html:
<div id="elm-area"><div>35</div></div>
```

 ブラウザにはこの３５という数字が表示されるだけです


# ２．Model-View-Update
　今度はボタンを設置して、表示する数字を増減させることができるようにします。前回と同じソースコードを以下に示します。

```elm:MyButtons.elm
module MyButtons exposing (..)

import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)

main =
  Html.beginnerProgram { model = model, view = view, update = update }

-- MODEL
type alias Model = Int

model : Model
model =
  0

-- UPDATE
type Msg = Increment | Decrement

update : Msg -> Model -> Model
update msg model =
  case msg of
    Increment ->
      model + 1

    Decrement ->
      model - 1

-- VIEW
view : Model -> Html Msg
view model =
  div []
    [ button [ onClick Decrement ] [ text "-" ]
    , div [] [ text (String.fromInt model) ]
    , button [ onClick Increment ] [ text "+" ]
    ]
```


　このプログラムは、内部的にカウンターを持っていて、インクリメントボタンとディクリメントボタンの２ボタンを表示し、間に現在値を表示しています。インクリメントボタンをクリックするとカウントアップした値が表示され、ディクリメントでカウントダウンした値が表示されます。特にブラウザをリフレッシュすることなしに、ブラウザ上の値は動的に変わっていきます。

　このモデルは以下のような流れになります。

```
　ユーザINPUTが発生 → modelを更新 → viewに更新を反映　→ ユーザINPUTが発生　→ ....
```

　これはElm RuntimeがユーザINPUTイベントの管理やHTML表示を司っているので、以下のように書くのがもっと正確です。

```
           (MSG)                        (Html)
Elm Runtime　→　update　→　model　→　view　→　Elm Runtime 
```

　上のようなモデルは以下のmain関数で定義されています。繰り返しになりますが、内部カウンター(model)をマウスクリックでupdateし、その結果をviewに反映させます。ユーザのINPUTをハンドリングし、modelをupdateし、そのupdateをviewに反映させます。これを繰り返すのがELM Architecture　の　Model-View-Update Loopです。

```elm:
main =
  Html.beginnerProgram { model = model, view = view, update = update }
```

　Html.beginnerProgram()はModel-View-Update Loopを実現化します。マウスでボタンが押されると（ユーザのINPUTがあると）、Elm RuntimeはMSG付きのイベントを発生させupdate関数を呼びます。update関数はMSGに従ってmodelを更新します。更新されたmodelでviewが呼ばれ、新しいHtmlが生成され、Elm Runtimeに渡され実際にブラウザで表示されます。つまりイベントとかDOM表示とかは全てElm Runtimeが下請けします。Virtual　DOMが使われていますが、Elm Runtimeは高速に描画してくれるらしいです。


　ちなみにElm Runtimeはコンパイラが生成してくれるJavaScriptコードです。ソースコードに従ってイベントハンドラーを設定してくれたり、HTTP RequestやDON updateの効率的なスケジューリングを行ってくれたりします。

　それと指摘しておきたいのがmodelですが、これはElmのデータですので直接書き換えることはできません。一部分を変更しながらコピーすることで、書き換えの代替としています。Elmは純粋ですから。


# ３．Type
　Haskellは型が強い言語です。コンパイラの型チェックがとても厳しくて、逆に型チェックが通れば、大方デバッグ無しで動くともいわれています。おなじようにElmにも型があります。上のプログラムで少し説明を加えます。

　以下はModelという方を定義しています。Int型の別名として定義されているのでaliasが付いています。

```elm:
type alias Model = Int
```

　以下はMsg型を定義しています。Msg型はIncrement または Decrement　のことを指します。

```elm:
type Msg = Increment | Decrement
```

　以下は関数updateの型です。Msg型とModel型の引数を取り、Model型の値を返します。

```elm:
update : Msg -> Model -> Model
```

　以下は関数viewの型です。Model型の引数を取り、Html Msg型の値を返します。Html Msg型にはtype variableのMsgが含まれています。Htmlは引数を必要とする方で、Html Msgではじめて一つの型になります。一般的にはHtml a で a
 がtype variableで任意の型が入ります。この場合はMsgがtype variableの値です。

```elm:
view : Model -> Html Msg
```

　今回は以上ですが、Elmの話はまだ続きます