関数型フロントエンド言語 Elm 0.18 のチュートリアルです。
- ブラウザだけで開発を始める
- シンプルなモデルの定義
- モデルの状態を画面に表示する
- アクションを定義してモデルの状態を更新する
WebでElmをはじめる
Ellie というオンラインエディタでElmを始めてみましょう。こちらはElmコードとそれを埋め込むためのHTMLコードをそれぞれ編集したり、Elmのパッケージを追加して開発することができます。

最初に書いてあるコードはElm側はテキストを表示するだけです。
module Main exposing (..)
import Html exposing (Html, text)
main : Html a
main =
text "Hello, World!"
一方HTML側では、Elmの呼び出しとCSSの記述があります。
<html>
<head>
<style>
html {
background: #F7F7F7;
color: red;
}
</style>
</head>
<body>
<script>
var app = Elm.Main.fullscreen()
</script>
</body>
</html>
文字が全部真っ赤だと辛いので、 color: red;
だけ消しておきましょう。
html {
background: #F7F7F7;
- color: red;
+ /*color: red;*/
}
コンパイルを実行すると反映されます。
以降のコードではHTML側は編集しません。
モデルを作って画面に表示する
では、アプリケーションの作成をしてみましょう。
Elmはアプリケーションの状態である「データモデル」を中心に、基本的に2つの処理を書きます。
- データモデルをHTML表示にする(View)
- データモデルをアクションに合わせて更新する(Update)
いきなり動きのあるアプリケーションを作る前に、まずはModelとViewから始めてみましょう。
アプリケーション全体のモデルとなる Model
型を作ります。 Int
そのものでも良いのですが、名前をつけてカウントを管理してみましょう。初期値は 0
としています。
type alias Model =
{ count : Int
}
initModel : Model
initModel =
{ count = 0
}
type alias Model
が型の定義部分で、 initModel : Model
は Model型の初期値を返す関数です。後ほど使います。
次に、先程は作らないと言っていた update
を作ります。ただし、定義するアクションは NoOp
(No Operation, 何もしない)のみです。
type Msg
= NoOp
update : Msg -> Model -> Model
update msg model =
case msg of
NoOp ->
model
内容は後述しますが、ここでは何もしないことだけを定義しています。
続いて view
の定義です。ElmではHTMLの記述も行います。
view : Model -> Html Msg
view model =
p []
[ text "count: "
, text (toString model.count)
]
view : Model -> Html Msg
はあるモデルの状態を受け取ってHTMLを返す関数で、
p
はHTMLタグ <p>
に対応しており、属性のリスト []
とタグの内容 [ text ... ]
の2つを受け取ってHtml
を返す関数です。
ただ、この状態ではコンパイルエラーが発生します。理由は、 p
がインポートされていないためです。 import
を修正しましょう。
-import Html exposing (Html, text)
+import Html exposing (Html, text, p)
最後に、アプリケーションとして機能するように関数を組み立てます。既に main
関数があると思いますが、一旦削除して次のように変更して下さい。
main : Program Never Model Msg
main =
Html.beginnerProgram
{ model = initModel
, update = update
, view = view
}
コンパイルしてプレビューに「count: 0」と表示されることを確認しましょう。
ここまでの全体像は次のようになります。
module Main exposing (..)
import Html exposing (Html, text, p)
main : Program Never Model Msg
main =
Html.beginnerProgram
{ model = initModel
, update = update
, view = view
}
type alias Model =
{ count : Int
}
initModel : Model
initModel =
{ count = 0
}
type Msg
= NoOp
update : Msg -> Model -> Model
update msg model =
case msg of
NoOp ->
model
view : Model -> Html Msg
view model =
p []
[ text "count: "
, text (toString model.count)
]
初期値を変更してみたりviewの内容をいじって再コンパイルしてみてください。
カウントアップを実装する
ボタンを押すとカウントアップする機能を実装してみましょう。
まず、アクションの種類を追加します。
type Msg
= NoOp
| Increase
type Msg = NoOp | Increase
という表記は、「 Msg
型の値は NoOp
または Increase
のどちらかである」ということを定義しています。 NoOp
などの具体的な定義がない、と思う方もいるかもしれませんが、 NoOp
はそれ自体がコンストラクタの役割も持っており、 Msg
型の値そのものです。
バックグラウンドを詳しく知りたい方は代数的データ型などを参照して下さい。
続いて、アクションへの具体的な対応(モデルの更新)を実装します。
update : Msg -> Model -> Model
update msg model =
case msg of
NoOp ->
model
Increase ->
{ model | count = model.count + 1 }
case msg of
は「パターンマッチ」です。ここでは Msg
の具体的な内容に応じて場合分けされていて、 NoOp
の場合は現在のmodelをそのまま返し、 Increase
の場合はモデルの更新を行っています。
{ model | ... }
はモデルの一部分だけを更新した新しいモデルを作る構文です。ここでは count
を現在のモデルのカウント model.count
に + 1
した新しいモデルを返しています。
この状態でコンパイルすることができますが、肝心の Increase
アクションを起こす方法を定義していません。
view
にボタンを作ってカウントアップできるようにしてみましょう。
view : Model -> Html Msg
view model =
div []
[ counter model
, increaseButton
]
counter : Model -> Html Msg
counter model =
p []
[ text "count: "
, text (toString model.count)
]
increaseButton : Html Msg
increaseButton =
div []
[ button [ onClick Increase ]
[ text "+1" ]
]
先程までの p
をカウンター表示用の関数 counter
から返すようにして、 increaseButton
を追加しました。 increaseButton
はモデルの状態によって変更する部分はないので Model
を引数に含めていません。
最後に、div
, button
タグやイベントを実行するための onClick
をインポートしましょう。
-import Html exposing (Html, text, p)
+import Html exposing (Html, text, p, div, button)
+import Html.Events exposing (onClick)
それではコンパイルして確認してみましょう。上手くカウントアップできているでしょうか?
ここまでのコードは以下で確認できます。
状態のリセットとデバッグ
このアプリケーションにはブラウザなどに状態を記録してはいないので、アプリケーションをリロードするとカウントが初期値に戻ります。プレビュー画面右下の「RELOAD」をクリックして確認してみましょう。
また、Elm 0.18では標準でデバッグモードを搭載しており、Eliieでも確認することができます。プレビュー画面左下の「DEBUG」をクリックしてみましょう。

アクションの履歴と、そのアクションが実行されたあとのモデルの状態が記録されており、クリックするとそのモデルの状態を画面で再現してくれます。
現在のモデルの状態に戻るには「Resume」をクリックします。
宿題
- カウントダウン
- "+5" ボタン
などを実装してみましょう。カウントダウンでマイナス値にならないように制御するにはどうすればよいでしょうか?
まとめ
Elm Architectureの一番簡単なモードである beginnerProgram
で小さなアプリケーションを作ってみました。いかがだったでしょうか?
モデルの定義とモデルを更新するためのアクション、そしてモデルの表示方法にきちんと分離されていてきれいな仕組みだと思います。
気になった方はぜひ自分なりのサンプルアプリケーションを作ってみて下さい。