Help us understand the problem. What is going on with this article?

フワッとわかった気になるElm入門

はじめに

Elm は、JavaScript に似た構文を持つ Web アプリケーションを作るための言語です。
本記事では HTML や JavaScript の例を交えながら、Elm についてフワッとわかった気になってもらうことを趣旨としてます。

前提知識

  • HTML と JavaScript を触ったことがある
  • 変数や関数、配列、オブジェクトについて知っている

注意

JavaScript に似た構文を持つ Elm ですが、異なる部分もあるので注意が必要です。1 2
特に、関数定義と関数呼び出しでは、括弧とカンマでなく、スペースを使います。
また、return がないことも特徴です。

JavaScript
function sum (x, y) { // 関数定義
    return x + y;
}

sum(1, 2); // 関数呼び出し


function puls1 (x) {
    return x + 1;
}

plus1(sum(1, 2))
Elm
sum x y = x + y; -- 関数定義

sum 1 2 -- 関数呼び出し


plus1 x = x + 1;

plus1 (sum 1 2)

また、 Elm には JavaScript にない、型注釈というものがありますが、いつかまた説明しましょう。

sum : Int -> Int -> Int -- 型注釈
sum x y = x + y; -- 関数定義

view 関数

まずは、以下のリンクを開いて、 -- VIEW 以下を見てみましょう
https://ellie-app.com/9WqRmw9Hkf9a1

45行目
-- VIEW


view : Model -> Html Msg
view model =
    div []
        [ button [] [ text "+" ]
        , div [] [ text "15" ]
        , button [] [ text "-" ]
        ]

このコードは、カウンターのボタンとカウンターの値を表示するだけです。
試しにボタンを触っても何も起きません。

view 関数で Web ページの見かけを作る

通常、Web ページに表示されるものは、HTML で記述されます。
例えば、ページのタイトル、次のページへのリンク、送信ボタン、など。

しかし、Elm では HTML の代わりに view 関数で Web ページを作ります。

view 関数に見出しを追加する

view 関数の中の div 関数や button 関数と、HTML の div タグや button タグを見比べると、よく似ていることがわかります。

HTML
    <div>
        <button>-</button>
        <div>15</div>
        <button>+</button>
    </div>
Elm
    div []
        [ button [] [ text "+" ]
        , div [] [ text "15" ]
        , button [] [ text "-" ]
        ]

試しに h1 関数で見出しを追加してみましょう。

-- VIEW


view : Model -> Html Msg
view model =
    div []
        [ h1 [] [ text "Hello World" ]
        , button [] [ text "+" ]
        , div [] [ text "15" ]
        , button [] [ text "-" ]
        ]

HTML の属性

HTML の要素の関数以外にも、HTML の属性の関数もあります。3
例えば class 関数や、id 関数、style 関数などです。

HTML
<h1 class="title" id="firstTitle" style="color:red">Hello, World</h1>
Elm
h1 [ class "title", id "firstTitle", style "color" "red" ] [ text "Hello World" ]

Model

今度は、 -- MODEL 以下を見てみましょう
https://ellie-app.com/9WqRmw9Hkf9a1

18行目
-- MODEL


type alias Model =
    { count : Int }


init : Model
init =
    { count = 0 }

Model で、Web ページの状態を作る

view 関数で、Web ページの見かけを作りましたが、このままではカウンターに表示されるのは常に同じ "15" という定数です。
この定数を変数にして、値を更新できるようにするために、Elm では Model を利用します。

type alias Model =
    { count : Int }

Model は、レコードという JavaScript のオブジェクトのようなものです。4
また、レコードの中の変数はフィールドと呼びます。

この count というフィールドが、カウンターの値となります。

view 関数で Model から Web ページを作る

view 関数では、model という値を受け取っていました。
そして model.count でカウンターの値を取り出すことができます。

-- VIEW


view : Model -> Html Msg
view model =
    div []
        [ button [] [ text "+" ]
        , div [] [ text "15" ]
        , button [] [ text "-" ]
        ]

view 関数の、text "15" の部分を、model.count に変えてみましょう。

-- VIEW


view : Model -> Html Msg
view model =
    div []
        [ button [] [ text "+" ]
        , div [] [ text (String.fromInt model.count) ]
        , button [] [ text "-" ]
        ]

ちなみに String.fromInt 関数 は、数値 (Int) を 文字列 (String) に変換する関数です。5
また後で説明しますが Elm ではこのように、値の変換をキッチリとしなければなりません。

init 関数で、Web ページの最初の状態を作る

Web ページにアクセスしたときの、Model の最初の値は、init 関数で決めることができます。

-- MODEL


type alias Model =
    { count : Int }


init : Model
init =
    { count = 0 }

試しに、最初のカウントを10からに変えてみましょう

-- MODEL


type alias Model =
    { count : Int }


init : Model
init =
    { count = 10 }

まとめ

  1. view 関数で Web ページを作る
  2. view 関数から表示を変化させたい値(Web ページの状態)を抜き出して Model を作る
  3. view 関数で Model から Web ページを作るようにする
  4. init 関数で Model の最初の値を作る

Msg と update 関数

次に、 -- UPDATE 以下を見てみましょう
https://ellie-app.com/9WqRVH9bQjma1

31行目
-- UPDATE


type Msg
    = Increment
    | Decrement


update : Msg -> Model -> Model
update msg model =
    model

Msg で「ユーザーが操作した、その次に起きること」を作る

画面のフォームに対して、ユーザーから何か操作があったとき、「その次に起きること」を表現してみましょう。
Msg は「ユーザーが操作した、その次に起きること」を表すものです。

今回は

  • + ボタンがクリックされたとき、「カウントが増える」
  • - ボタンがクリックされたとき、「カウントが減る」

の2つです。

-- UPDATE


type Msg
    = Increment
    | Decrement

Increment は「カウントが増える」ということを表し、Decrement「カウントが減る」ということを表しています。

さて HTML のイベントが起きたときに、Msg の値が通知されるようにしましょう。

-- VIEW


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


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

onClick 関数は、HTML のイベント属性である onclick を表しています。

そして、ここで通知された Msg の値が、次の update 関数に渡されます。

update 関数で「実際に何が起きるか」を作る

update 関数は、受け取った Msg に連動して「実際に何が起きるか」を表すものです。
具体的には、update 関数は、受け取った Msg によって分岐して Model を更新する関数です。

それでは
- 受け取った msg が Increment ならば model.count を1増やす
- 受け取った msg が Decrement ならば model.count を1減らす
この2つの処理を書いてみましょう。

-- UPDATE


type Msg
    = Increment
    | Decrement


update : Msg -> Model -> Model
update msg model =
    case msg of
        Increment ->
            { model | count = model.count + 1 }

        Decrement ->
            { model | count = model.count - 1 }

case msg of は JavaScript の switch 文のようなものです。6
msg が Increment のときと、Decrement のときで分岐することを表しています。

また、{ xxx | ~~ } はレコードを更新する構文です。
例えば、{ model | count = model.count + 1}は、 model.count + 1 を新しい model.count としたレコードを作る、という意味です。

ここで作られた新しい Model が view 関数に渡り、Web の表示が更新されます。

まとめ

おめでとうございます!
ついに、カウンターが動くようになりました。
https://ellie-app.com/9WqWzcqp3nra1

ここまでの手順をまとめてみましょう。

  1. view 関数からユーザーが操作した、その次に起きることを抜き出して Msg を作る
  2. view 関数で、HTML のイベントが起きたときに、Msg の値が通知されるようにする
  3. update 関数で、受け取った Msg によって処理が分岐し Model を更新する処理を作る

The Elm Architecutre

ここまでの一連の流れがつかめたでしょうか?

  1. init 関数で Model の最初の値を定めて、view 関数に渡される
  2. view 関数で 渡された Model によって Web ページが表示される
  3. ユーザーの操作があると Msg が通知され、update 関数に渡される
  4. update 関数で Msg によって処理が分岐し、 Model が更新されて view 関数に渡される
  5. 1.へ戻る

TEAPractice.png

このようなサイクルを繰り返して、画面が動くようになりました!

これが The Elm Architecutre です。
そんなに難しくないでしょう?

全体のまとめ

処理を作る流れ

  1. view 関数で Web ページを作る
  2. view 関数から表示を変化させたい値(Web ページの状態)を抜き出して Model を作る
  3. view 関数で Model から Web ページを作るようにする
  4. init 関数で Model の最初の値を作る
  5. view 関数からユーザーが操作した、その次に起きることを抜き出して Msg を作る
  6. view 関数で、HTML のイベントが起きたときに、Msg の値が通知されるようにする
  7. update 関数で、受け取った Msg によって処理が分岐し Model を更新する処理を作る

実際の処理の流れ

  1. init 関数で Model の最初の値を定めて、view 関数に渡される
  2. view 関数で 渡された Model によって Web ページが表示される
  3. ユーザーの操作があると Msg が通知され、update 関数に渡される
  4. update 関数で Msg によって処理が分岐し、 Model が更新されて view 関数に渡される
  5. 1.へ戻る

TEAPractice.png

完成品

https://ellie-app.com/9WqWzcqp3nra1

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした