Elm のディレクトリ構成とプロジェクトのつくりかた

> この記事の内容はElm 0.18向けのもので少し古いです。
> また、Routingに関して考慮されていないのでSPA開発向けでもありません。
> Elm 0.19のディレクトリ構成に関しては[elm-spa-example](https://github.com/rtfeldman/elm-spa-example)が参考になります。

これは [Elm Advent Calendar 2017](https://qiita.com/advent-calendar/2017/elm) の 22 日目の記事です。

はじめまして、@hennin です。Qiita デビューです。

「[Elm チュートリアル](https://www.elm-tutorial.org/jp/)は一応読んだ。
　で、実際どういう感じでプロジェクトつくってくの？」

今回はそういうお話です。

ちなみに今回作成したプロジェクトはこちら。

https://github.com/henninltn/elm-sample




# この記事を読む前に

この記事は以下の記事の内容を大いに参考にしています。
ガイドラインの題名と図だけでもいいのでさらっと見ておくといいかもです。

[Nine Guidelines for Modular Elm Development – im-becoming-functional](https://becoming-functional.com/nine-guidelines-for-modular-elm-development-fe18d2f7885e)

あと、環境構築で詰まっている人は10日目の @ahuglajbclajep さんの記事がとても参考になりますのでぜひ。

[Elmに入門してみて思ったこと](https://qiita.com/ahuglajbclajep/items/1f36073cacfc7b995cfd)




# ディレクトリ構成

プロジェクトを作成する上で一番気になるのはやっぱりディレクトリ構成ですよね。

プロジェクトの進めやすさはディレクトリ構成で決まると言っても過言ではありません。(※個人の見解です)

ディレクトリ構成には大きく分けて縦割りと横割りの2種類があると思うんですよね。



## 縦割り

Elm チュートリアルでも紹介されているやり方ですね。

```
root/
   ├ Foo/
   │   ├ Model.elm
   │   ├ Update.elm
   │   └ View.elm
   │
   ├　Bar/
   │   ├ Model.elm
   │   ├ Subscriptions.elm
   │   ├ Update.elm
   │   └ View.elm
   │
   ├ Main.elm
   ├ Model.elm
   ├ Subscriptions.elm
   ├ Update.elm
   └ View.elm
```

コンポーネントで分ける感じです。

実装がコンポーネントごとにまとまってるので分かりやすいですね。

ただこれ、作ってみると分かりますけどコンポーネント単位で再利用することってあんまりないんですよね。
まあ実際のプロジェクトでは汎用コンポーネントより具体的なコンポーネントを作ることの方が多くなるのは当たり前です。

それに、コンポーネント単位で再利用するより`Model`とか`view`の単位で再利用する方がお手軽ですよね。

というわけで、シンプルを目指すElmでは次に紹介する[横割り](#横割り)を採用する方がいいようです。

ちなみにですけど、`Msg`は`Model`の中に書いちゃってます。
`Msg`と`Model`は基本セットで`import`されるので、その方が色々と楽なんですよね。



## 横割り

どこでもわりとよく見かける分け方ですね。

```
root/
   ├ Model/
   │   ├ Foo.elm
   │   ├ Bar.elm
   │   ├ Hoge.elm
   │   └ Fuga.elm
   │
   ├ Subscriptions/
   │   └ Bar.elm
   │
   ├ Update/
   │   ├ Foo.elm
   │   └ Bar.elm
   │
   ├ View/
   │   ├ Header.elm
   │   ├ Foo.elm
   │   └ Bar.elm
   │
   ├ Main.elm
   ├ Model.elm
   ├ Subscriptions.elm
   ├ Update.elm
   └ View.elm
```

種類ごとに分ける感じです。

利点としては、それぞれのディレクトリ内で使いまわせる関数や型を作るのが簡単なことが挙げられますね。
`Model`内全体で使うモデルとか、`View`内の色々なところで呼び出すビューの関数とか。

書いてる感じ`Model`のファイル数が結構多くなりますね。

`Msg`をもつ`Model`のファイル数と`Update`のファイル数はまあ一致します。というか一致させるものですよねこれ(たぶん)。

ちなみに`Model`は対応する`Msg`があるものとないものに分けられます(これもたぶん)。

`View`も`Msg`や`Update`よりファイル数が多くなりそうです。まあ状態を持つ(つまり Model の更新によって動作などが変わる)部分と持たない部分がありますからね。

とまあ、ディレクトリ構成はこんな感じでしょうか。




# モジュールの分け方

Elm チュートリアルに[コンポーネントの分け方を説明しているところ](https://www.elm-tutorial.org/jp/02-elm-arch/06-composing.html)がありましたよね。

そこでは上位の`Update`から下位の`Update`を呼び出したり、上位の`Msg`の値コンストラクタに下位の`Msg`を持ったものを定義したりしてました。

正直これちんぷんかんぷんじゃないですか？

というわけで、これを理解するための説明を行っていきたいと思います。

完成したリポジトリはこちら。

https://github.com/henninltn/elm-sample


### Elmアーキテクチャ

モジュールの分け方を理解する上で、Elmアーキテクチャを理解しておくことはとても重要だと思います。

ですので、Elmアーキテクチャについてすごーく簡単に説明してみたいと思います。

1. ユーザーは`Model`、`Msg`、`update`、`view`をそれぞれ1つだけ書く
2. コンパイル時に以下の処理が加えられたHtml/JavaScriptコードが生成される

以下は最終的に生成されるコードの処理の流れです。

![elm-architecture-flow.png](https://qiita-image-store.s3.amazonaws.com/0/225715/e9a3f249-14a9-986c-1f62-750a734aad23.png)

加えられた後の処理の流れとしては、

1. `Runtime`から`view`に`Model`が渡され、描画される
2. `view`内ではイベント発火時に`Runtime`に`Msg`が投げられる
3. `Runtime`では`Msg`が投げられると、`update`にその`Msg`と`Runtime`が保持する`Model`が渡され実行される
4. `update`から返却された`Model`によって`Runtime`の保持する`Model`が書き換えられる
5. 1.に戻る

という感じになります。

`Runtime`については、Elmのコンパイル時に加えられる隠蔽された処理の塊みたいなものと思ってください。

`Cmd`とここには登場していない`Sub`については後の[Elmでの副作用の扱い方](#elmでの副作用の扱い方)で説明しますね。

ここで覚えておいてほしいのは、以下の4つのことです。

- Elm アーキテクチャは以下の 2 つの型と 2 つの関数からなる
  - `Model`
  - `Msg`
  - `update : Msg -> Model -> (Model, Cmd Msg)`
  - `view : Model -> Html Msg`
- `Model`はアプリケーションでインスタンスが1つのみ、`init`関数を定義して生成することが多い
- `update`と`view`はアプリケーションで1つだけ
- `Msg`はアプリケーションで1つの型のインスタンスのみ

とてもシンプルですね。
副作用を扱うことを考えると、ここに`Cmd`と`Sub`が加わりますけど。

でもこれだと大きなものを作ろうとすると、`Msg`の数が増え、`update`のパターンマッチも複雑になっていきます。

そこで`Model`、`Msg`、`update`、`view`を複数の型や関数、ひいてはモジュールに分けていくことを考えます。

ここで横割りの登場ですね。


### サンプルプロジェクト

以下の1ファイルのプロジェクトをモジュールに分けていきたいと思います。

ユーザーと企業を管理する簡単なアプリケーションです。

まあ管理といっても追加しか機能がありませんけど。

```elm
import Html exposing (program, div, Html, text, input, button)
import Html.Attributes exposing (value)
import Html.Events exposing (onInput, onClick)


type Msg
    = UpdateUserNameField String
    | AddUser
    | UpdateCompanyNameField String
    | AddCompany


type alias User =
    { name : String }


type alias Company =
    { name : String }


type alias Model =
    { userNameField : String
    , companyNameField : String
    , users : List User
    , companies : List Company
    }


init : ( Model, Cmd Msg )
init =
    ( { userNameField = ""
      , companyNameField = ""
      , users = []
      , companies = []
      }
    , Cmd.none
    )


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        UpdateUserNameField str ->
            ( { model | userNameField = str }, Cmd.none )

        AddUser ->
            ( { model
                | users = { name = model.userNameField } :: model.users
                , userNameField = ""
              }
            , Cmd.none
            )

        UpdateCompanyNameField str ->
            ( { model | companyNameField = str }, Cmd.none )

        AddCompany ->
            ( { model
                | companies = { name = model.companyNameField } :: model.companies
                , companyNameField = ""
              }
            , Cmd.none
            )


userView : User -> Html Msg
userView user =
    div []
        [ text "User: "
        , text user.name
        ]


companyView : Company -> Html Msg
companyView company =
    div []
        [ text "Company: "
        , text company.name
        ]


view : Model -> Html Msg
view model =
    div []
        [ div []
            [ input [ value model.userNameField, onInput UpdateUserNameField ] []
            , button [ onClick AddUser ] [ text "Add" ]
            ]
        , div []
            (model.users |> List.map userView)
        , div []
            [ input [ value model.companyNameField, onInput UpdateCompanyNameField ] []
            , button [ onClick AddCompany ] [ text "Add" ]
            ]
        , div []
            (model.companies |> List.map companyView)
        ]


main : Program Never Model Msg
main =
    program
        { init = init
        , view = view
        , update = update
        , subscriptions = (\_ -> Sub.none)
        }
```

`input`の入力値は`Model.userNameField`と`Model.companyNameField`に持たせておき、入力があるたびにこれらの値を`input`に入力されている現在値で更新していきます。

`onInput`は入力があるたびに現在入力されている値を引数の`Msg`に渡すようですね。

そして`button`が押された時にメッセージ`Add`を飛ばして`update`を実行することで、ユーザーもしくは企業を追加しています。

「`User`と`Company`名前違うだけで中身全く同じじゃねえか」とか言ってはいけません。

サンプルですからね。


### MsgとModelの分け方

まずは下位の(`Users`と`Companies`の)`Msg`と`Model`を定義していきます。

```elm:Model/Users.elm
type Msg
    = UpdateNameField String
    | Add


type alias User =
    { name : String }


type alias Model =
    { nameField : String
    , users : List User
    }
```

一部省略です。
詳しくは[完成版のプロジェクト](https://github.com/henninltn/elm-sample)を参照してください。

ユーザー管理に関係するUIの状態(`nameField`)とデータ(`users`)をまとめただけですね。

`Companies`は名前違うだけなのでこれも省略です。

「じゃあなんで作ったんだ」と言われそうですけど、それは「モジュール分けないと`userNameField`とか`companyNameField`とか名前被ってくるし複雑になるから分けたくならない？」みたいな話です。

そして`Model`と`Msg`はアプリケーションで1つなので、当然これらを1つにまとめる必要がありますよね。

```elm:Model.elm
type Msg
    = UsersMsg Users.Msg
    | CompaniesMsg Companies.Msg


type alias Model =
    { usersModel : Users.Model
    , companiesModel : Companies.Model
    }
```

`Model`は見たまんまです。

`Msg`は、**下位の`Msg`を引数にもつ値コンストラクタ**を定義することで、下位の`Msg`も合わせて1つの`Msg`のインスタンスってことにしちゃうんですね。

この引数に渡された下位の`Msg`は次の[updateの分け方](#updateの分け方)でパターンマッチを使って取りだします。

ちなみにですけど`import`は

```elm
import Model.Users as Users
import Model.Companies as Companies
```

みたいにしてます。
以下の`update`でも`view`でも大体こんな感じですね。


### updateの分け方

まずは`Users`用の`update`を定義します。

```elm:Update/Users.elm
import Model.Users as Users exposing (Msg(..), Model)


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        UpdateNameField str ->
            ( { model | nameField = str }, Cmd.none )

        Add ->
            ( { model
                | users = { name = model.nameField } :: model.users
                , nameField = ""
              }
            , Cmd.none
            )
```

こちらも一部省略です。
以下でも特に断らない限りは重量なところだけ抜粋したコードを載せていきます。

`Model.Users.Model`のためだけの`update`なのでとてもシンプルになりましたね。

例によって`Model.Companies.Model`用の`update`は省略。

そして`update`もアプリケーションに1つなのでまとめていきます。

```elm:Update.elm
import Model exposing (Msg(..), Model)


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        UsersMsg subMsg ->
            let
                ( updatedUsersModel, usersCmd ) =
                    Users.update subMsg model.usersModel
            in
                ( { model | usersModel = updatedUsersModel }
                , Cmd.map UsersMsg usersCmd
                )

        CompaniesMsg subMsg ->
            let
                ( updatedCompaniesModel, companiesCmd ) =
                    Companies.update subMsg model.companiesModel
            in
                ( { model | companiesModel = updatedCompaniesModel }
                , Cmd.map CompaniesMsg companiesCmd
                )
```

簡単に説明していきますね。

まずパターンマッチで`UsersMsg`から`Model.Users.Msg`のインスタンスを`subMsg`として取り出します。

そして下位の`update`である`Update.Users.update`を使って、更新後の`Model.Users.Model`である`updatedUserModel`と、更新後の`Cmd Model.Users.Msg`である`usersCmd`を手に入れます。

`Update.Users.update`の型は`update : Model.Users.Msg -> Model.Users.Model -> (Model.Users.Model, Cmd Model.Users.Msg)`ですからね。

あとはその結果を`(Model.Model, Cmd Model.Msg)`に変換して返すだけですね。

その変換を行っているのが`Html.map`で、`Cmd Model.Users.Msg`を`Cmd Model.Msg`に変換しています。

この`map`なんですけど、これからも色々なところで出てきますので厳密さよりイメージ重視で説明しておきますね。

ようは「**ひとつ下の型に関数を適用するもの**」です。

だから`Cmd Model.Users.Msg`に`UsersMsg : Model.Users.Msg -> Model.Msg`を`map`すると`Cmd Model.Msg`になるんですね。

値コンストラクタである`UsersMsg`はただの関数であることを思い出すとまあ何となく分かるんじゃないでしょうか。

あと、Elmは強い静的型付けの言語なので型を見ると理解しやすいです。

例えば`Cmd.map`の型は`map : (a -> msg) -> Cmd a -> Cmd msg`なので、「値コンストラクタ(`a -> msg`)と下位の`Msg`をもつ`Cmd`(`Cmd a`)を渡すと、上位の`Msg`をもつ`Cmd`(`Cmd msg`)が返ってくるのかなあ」ってなんとなくわかりますよね。

`a`と`msg`は型パラメータなので好きな型を入れられます。
まあ大体`a`は変換前の`Msg`の型、`msg`は変換後の`Msg`の型ですけどね。

そして`CompaniesMsg`はほとんど同じなので以下略。


### Viewの分け方

あんまり説明することがない気がするので雑めにいきます。そ〜れ〜。

```elm:View/Users.elm
import Model.Users exposing (Msg(..), Model, User)


userView : User -> Html Msg
userView user =
    div []
        [ text "User: "
        , text user.name
        ]


view : Model -> Html Msg
view model =
    div []
        [ div []
            [ input
                [ value model.nameField
                , onInput UpdateNameField
                ]
                []
            , button [ onClick Add ] [ text "Add" ]
            ]
        , div []
            (model.users |> List.map userView)
        ]
```

`Companies`は以下略。

これもまとめていきます。

```elm:View.elm
import Model exposing (Msg(..), Model)


view : Model -> Html Msg
view model =
    div []
        [ Html.map UsersMsg (Users.view model.usersModel)
        , Html.map CompaniesMsg (Companies.view model.companiesModel)
        ]
```

さっそく出てきました、`Html.map`です。

ここでは`map`は、`Users.view model.usersModel`の返り値が`Html Model.Users.Msg`なので`Html Model.Users.Msg`を`Html Model.Msg`に変換してますね。

型を見ると`map : (a -> msg) -> Html a -> Html msg`となっているので、「1つ目の引数の関数`a -> msg`を使って`Html a`を`Html msg`に変換できるのかなあ」ってこれもまた何となくわかりますよね。

1つめの関数っていうのはもちろん値コンストラクタですよ。


### 定義してきたものを`Runtime`に渡す

ここまでくれば、あとは今まで定義してきた`Model`、`update`、`view`を`Runtime`に渡すだけですね。

```elm:Main.elm
main : Program Never Model Msg
main =
    program
        { init = ( init, Cmd.none )
        , view = view
        , update = update
        , subscriptions = subscriptions
        }
```

`init`は各`Model`の中でその`Model`の初期値を返す関数として定義して、例によって`Model.elm`で1つにまとめたやつです。

想像がつかないという人は[完成版のプロジェクト](https://github.com/henninltn/elm-sample)を見てください。

`subscriptions`については後の[Sub](#sub)で説明します。

あとはコンパイルすれば`Runtime`の処理を加えたHtml/JavaScriptコードが生成されますね。

ここまでくればElmの基本的な流れは何となく理解できたのではないでしょうか。

`Model`、`Msg`、`update`、`view`の流れがあやふやな人は[Elmアーキテクチャ](#elmアーキテクチャ)の図を見返してくださいね。

というわけで、ここからはElmでの副作用の扱い方について説明していこうかなと思います。




# Elmでの副作用の扱い方

Elmは純粋関数型言語なので副作用がありません。

ただこれはユーザーが直接副作用を扱えないというだけで、実は`Runtime`内で副作用は起こされてるんですよね。

だってそうじゃないと画面の描画すらできませんからね。

というわけで、ここからはElmでの副作用の扱い方を見ていきます。

主には`Cmd`、`Sub`を使います。
あとは`JavaScript`を使える`Ports`ですね。



## Cmd、Sub

`Cmd`と`Sub`はどちらもすでに`Runtime`に用意されている副作用をともなう処理を利用するものです。

`Random`とかElmのcoreライブラリに組み込まれてますね。

`Cmd`、`Sub`のサンプルについて今回つくるプロジェクトでは`CmdSubSample`という名前で実装していきます。

https://github.com/henninltn/elm-sample

### Cmd

`Cmd`は`Runtime`に対して「`Runtime`に用意されている副作用のある関数を実行して、結果の値だけくれ」と命令するものです。

処理自体は`Runtime`が行うので、ユーザーが書くコードでは参照透過性が保たれるというわけです。

屁理屈みたいに聞こえましたか？
でもこれで「すべての関数は同じ入力に対して同じ出力のみを返す」っていうのが守られるんですよ。

だって`Runtime`に「副作用起こして」と命令する`Msg`はただの値ですからね。

`Cmd`は`update`から投げることができ、結果の値は任意の`Msg`として受け取ることができます。

```elm:Model/CmdSubSample.elm
type Msg
    = Roll
    | OnResult Int


type alias Model =
    { rollResult : Int
    }
```

```elm:Update/CmdSubSample.elm
import Model.CmdSubSample exposing (Msg(..), Model)
import Random


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Roll ->
            ( model, Random.generate OnResult (Random.int 1 6) )

        OnResult res ->
            ( { model | rollResult = res }, Cmd.none )
```

サイコロを振る例ですね。
重要なところだけ抜粋です。

`Random.generate`の型は`generate : (a -> msg) -> Generator a -> Cmd msg`となっています。

つまり「`Msg`の値コンストラクタと`Generator a`を受け取って、`Cmd msg`を返す」関数となります。

噛み砕いて説明しちゃうと、`Generator a`で「どんな副作用を起こしてどんな結果(`a`)を得るか」を指定して、`a -> msg`で「その結果(`a`)をどの`Msg`として受け取るか」を決めてるんですね。

`View.CmdSubSample.view`は`Model.CmdSubSample.Model.rollResult`の値を表示しているだけなので省略です。


### Sub

こっちは主に外部入力系の副作用を扱います。
キーボード、マウス、タイマーとかですね。

`Sub`は`Runtime`に対して「この入力があったときにこの`Msg`を投げて」という指示を行います。

もちろん`Sub`も参照透過性が保たれます。

```elm:Model/CmdSubSample.elm
type Msg
    = MouseMsg Position
    | KeyMsg KeyCode


type alias Model =
    { mousePosition : Position
    , downedKey : Maybe KeyCode
    }
```

```elm:Update/CmdSubSample.elm
import Model.CmdSubSample exposing (Msg(..), Model)


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        MouseMsg position ->
            ( { model | mousePosition = position }, Cmd.none )

        KeyMsg keyCode ->
            ( { model | downedKey = Just keyCode }, Cmd.none )
```

```elm:Subscriptions/CmdSubSample.elm
import Model.CmdSubSample exposing (Msg(..), Model)


subscriptions : Model -> Sub Msg
subscriptions _ =
    Sub.batch
        [ Mouse.clicks MouseMsg
        , Keyboard.downs KeyMsg
        ]
```

見たまんまですね。

マウスのクリックイベントが発火されたとき、`MouseMsg`が送信されます。
これは`Runtime`ですでに用意されている処理ですね。

`Sub.batch`で`Sub`の複数指定ができるみたいですね。
型は`batch : List (Sub msg) -> Sub msg`ですので、複数の`Sub`を1つにまとめてるだけです。

`Position`型と`KeyCode`型についてはそれぞれ[Mouse - mouse 1.0.1](http://package.elm-lang.org/packages/elm-lang/mouse/1.0.1/Mouse)、[Keyboard - keyboard 1.0.1](http://package.elm-lang.org/packages/elm-lang/keyboard/1.0.1/Keyboard)をそれぞれ参照してみてください。
まあ`KeyCode`は[Char - core 5.1.1](http://package.elm-lang.org/packages/elm-lang/core/latest/Char)で定義されてるのと一緒なんですけどね。

ちなみに`Sub`も`Subscriptions/`というディレクトリを作ります。
`subscriptions`は`Model`を受け取るので、`update`と同じような感じで分ければ大丈夫ですね。

もちろん最後はまた`Sub.batch`を使って1つにまとめます。

```elm:Subscriptions.elm
import Model exposing (Model, Msg(..))


subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.batch
        [ Sub.map
            CmdSubSampleMsg
            (CmdSubSample.subscriptions model.cmdSubSampleModel)
        ]
```

そろそろ慣れてきたんじゃないでしょうか、おなじみの`map`です。

`Sub Model.CmdSubSample.Msg`を`Sub Model.Msg`に変換しています。
`CmdSubSampleMsg : Model.CmdSubSample.Msg -> Model.Msg`をそのまま使ってますね。

`Sub.map`の型は`map : (a -> msg) -> Sub a -> Sub msg
`です。
もうそろそろ型も読めるようになってきたんじゃないですかね？(無茶振り

読めそうになかったら[updateの分け方](#updateの分け方)の`Html.map`の説明の部分をもう一度読み返してみてください。

あとはこれを`main`関数で`Runtime`に渡すだけです。
まあ省略するんですけど。



## Ports

`Cmd`と`Sub`はどちらも`Runtime`、つまりElmのcoreライブラリですでに用意されているものを使うことが前提でした。

ではライブラリで提供されていないような副作用を扱いたいときはどうするのでしょうか。

それを解決してくれるのが`Ports`です。

ようは`Runtime`に独自に処理を加えることができる機能ですね。

`Ports`のサンプルの実装は`PortsSample`という名前で行っていきます。

詳細は以下の今回作成したプロジェクトを参照してください。

https://github.com/henninltn/elm-sample

また、`Ports`については以下の記事を参考にさせていただきました。

[ElmのPortでJSを使う。 - Qiita](https://qiita.com/jooex/items/5ff2d3b86563cf5dbd84)

Elmの型とJavaScriptの型の対応表とか乗ってるので、必要になったときに参考にするといいと思います。


### ElmからRuntime(JavaScript)の呼び出し

JavaScriptで書いた処理を`Runtime`に組み込んで、Elmから呼び出せるようにします。

呼び出しには`Cmd`を使います。
coreライブラリで用意された`Cmd`の使い方と一つ違うのは、値が返ってこないことですね。

`Random`とかの`Cmd`は、結果を`Msg`で受け取れましたからね。

返ってきた値を受け取る方法は下の[Runtime(JavaScript)からElmの呼び出し](#runtimejavascriptからelmの呼び出し)で説明します。

`Runtime`に組み込みたいものはモジュール単位で作成します。
モジュール宣言時に`port module`と書くだけです。

また`Ports`は既存の`Model`、`view`、`update`、`subscriptions`のいずれにも属しませんので、新たに`Ports/`というディレクトリをつくります。

あと、`Ports`を使う場合はElm単体からHtml/JavaScriptへコンパイルするのではなく、JavaScriptからElmを呼び出す方法を使うことになります。

[チュートリアル](https://www.elm-tutorial.org/jp/04-starting/03-webpack-1.html)でWebpack使ってやったやつですね。

```elm:Ports/Console.elm
port module Ports.Console exposing (log)


port log : String -> Cmd msg
```

```javascript:public/index.js
const Elm = require("../src/Main.elm");
const mountNode = document.getElementById("root");
const app = Elm.Main.embed(mountNode);

app.ports.log.subscribe(function(str) {
  console.log(str);
});
```

`Ports`では中身の実装を`JavaScript`に任せるため、関数の型宣言だけを行います。
あと型宣言には`port`を付けます。

`port module`内には普通の関数も書けるので、差別化のためですね。

`subscribe`は「購読する」という意味で、プログラミングでは何かの合図を待ち受けて処理を実行するときによく使われます。

ここではElmからの関数の呼び出しを合図に引数の関数を実行するという意味になりますね。

coreライブラリの`Cmd`では`Cmd Msg`の`Msg`で結果の値を受け取ってましたけど、Portsではパラメータ多層を使って`Cmd msg`とします。

でもこれ、`msg`はどこいっちゃうんでしょうね。(誰か教えて……

使い方はcoreライブラリの`Cmd`と一緒です。(ただし`Msg`は返ってこない)

まあ今回は`Cmd`の初期値として渡してみます。

```elm:Main.elm
main : Program Never Model Msg
main =
    program
        { init = ( init, Console.log "Hellow, world!" )
        , view = view
        , update = update
        , subscriptions = subscriptions
        }
```

これでプログラムが起動されたタイミングで実行されます。
詳しいタイミングは知らないですけどね。

気になる方は調べてみるといいんじゃないでしょうか。(丸投げ


### Runtime(JavaScript)からElmの呼び出し

こっちは`Sub`で利用できるタイミングを自分で実装する感じですね。

上の[Sub](#sub)で`Mouse.clicks`などがありましたが、これみたいなのを自分で実装して`Runtime`に加えます。

こっちは先ほどの[ElmからRuntime(JavaScript)の呼び出し](#elmからruntimejavascriptの呼び出し)と違ってcoreライブラリの`Sub`と完全に一緒ですね。

例として`Mouse.clicks`を自分で実装してみます。

```elm:Ports/MyMouse.elm
port module Ports.MyMouse exposing (Position, clicks)


type alias Position =
    { x : Int
    , y : Int
    }


port clicks : (Position -> msg) -> Sub msg
```

```javascript:public/index.js
const Elm = require("../src/Main.elm");
const mountNode = document.getElementById("root");
const app = Elm.Main.embed(mountNode);

document.body.addEventListener("click", function(e) {
  app.ports.clicks.send({ x: e.clientX, y: e.clientY });
});
```

そんなに難しいところはないですね。

あとは`Sub`として利用するだけです。

```elm:Model/PortsSamle.elm
type Msg
    = MouseMsg Position


type alias Model =
    { mousePosition : Position
    }
```

```elm:Update/PortsSample.elm
import Model.PortsSample exposing (Msg(..), Model)


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        MouseMsg position ->
            ( { model | mousePosition = position }, Cmd.none )
```

```elm:Subscriptions/PortsSample.elm
import Model.PortsSample as PortsSample exposing (Msg(..), Model)


subscriptions : Model -> Sub Msg
subscriptions _ =
    Sub.batch
        [ MyMouse.clicks MouseMsg
        ]
```

クリックされたとき`Model.mousePosition`が更新されます。

`view`は省略してますけど`Model.mousePositions`を表示させてるだけですね。

そして`Subscriptions`も例によって例のごとく1つにまとめてしまいます。

```elm:Subscriptions.elm
subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.batch
        [ Sub.map
            PortsSampleMsg
            (PortsSample.subscriptions model.portsSampleModel)
        ]
```

`Sub.map`はもう大丈夫ですね。

`Subscriptions.PortsSample.subscriptions`は`Model.PortsSample.Msg`を返しますが、これを`Model.Msg`を返すように変換します。

型は`map : (a -> msg) -> Sub a -> Sub msg`でしたね。

もう読めますよね。


### PortsのCmdっぽい使い方

[Runtime(JavaScript)からElmの呼び出し](#runtimejavascriptからelmの呼び出し)はcoreライブラリの`Sub`と同じでしたけど、なぜか[ElmからRuntime(JavaScript)の呼び出し](#elmからruntimejavascriptの呼び出し)の方はcoreライブラリの`Cmd`と違ってそれ単体では結果を`Msg`で受け取ることができませんでしたよね。

ではどうやって結果の値を受け取るのかというと、これらを両方使います。

`JavaScript`側でごにょごにょやっちゃうんですけど、これはコードを見てもらった方が早い気がするので説明放棄です。

```elm:Ports/Greeting.elm
port module Ports.Greeting exposing (fetchGreeting, receiveGreeting)


port fetchGreeting : String -> Cmd msg


port receiveGreeting : (String -> msg) -> Sub msg
```

```javascript
const Elm = require("../src/Main.elm");
const mountNode = document.getElementById("root");
const app = Elm.Main.embed(mountNode);

app.ports.fetchGreeting.subscribe(function(name) {
  app.ports.receiveGreeting.send("Hello, " + name + "!");
});
```

こんな感じです。

`fetchGreeting`でElmから`Runtime`(JavaScript)の`subscribe`のコールバック関数を実行。
コールバック関数はElmから飛んできた`Msg`の中身を引数として受け取ってますね。

で、そのコールバック関数の中でElmの`receiveGreeting`を実行。
入力された名前に挨拶する文字列がElm側に送信され、下の`subscriptions`で設定された`Msg`に載せられて送信されるわけですね。

そんなに難しくないんじゃないかなあと思います。

そして使い方ですね。`Cmd`と`Sub`を両方使います。

```elm:Model/PortsSample.elm
type Msg
    = UpdateNameField String
    | FetchGreetingMsg String
    | ReceiveGreetingMsg String


type alias Model =
    { nameField : String
    , greeting : String
    }
```

```elm:Update/PortsSample.elm
import Model.PortsSample exposing (Msg(..), Model)


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        UpdateNameField str ->
            ( { model | nameField = str }, Cmd.none )

        FetchGreetingMsg name ->
            ( model, Greeting.fetchGreeting name )

        ReceiveGreetingMsg greeting ->
            ( { model | greeting = greeting }, Cmd.none )
```

```elm:View/PortsSample.elm
view : Model -> Html Msg
view { mousePosition, nameField, greeting } =
    div []
        [ mousePositionView mousePosition
        , greetingView nameField greeting
        ]


greetingView : String -> String -> Html Msg
greetingView nameField greeting =
    div []
        [ label []
            [ text "name: " ]
        , input
            [ value nameField
            , onInput UpdateNameField
            ]
            []
        , button
            [ onClick (FetchGreetingMsg nameField) ]
            [ text "FetchGreeting" ]
        , div []
            [ text greeting ]
        ]
```

はい、コード読めば分かりますね。(暴言)

まあ実際[Elmアーキテクチャ](#elmアーキテクチャ)の図を思い返してもらえれば読めるんじゃないかなあと思います。

`view`の`fetchGreeting`から読み始めるといいのではないでしょうか。

「なんか雑すぎない？」
はい、そうですね。

でもこれはあれですよ、みなさんの練習になるかと思ってちょっとずつ説明減らしてきただけですからね。
記事の後半になって面倒になってきたとかそういうわけでは決してないんですよ、決して。

`Subscriptions.elm`はさっきと同じなので省略です。




# まとめ

結構長くなってしまいましたけど、このあたりで終わろうかと思います。

今回やったことは大きくは以下の3つですね。

- ディレクトリ構成
- モジュールの分け方
- 副作用の扱い方

これでとりあえずはElmでプロジェクトを書き始められるのではないでしょうか。

応用は書きながら追々やっていく感じですね。

[elm-test](https://github.com/elm-community/elm-test)入れたり、SassとかLESSのコンパイル入れたり。

まあ次はテトリスでも書いて記事にできたらなあと思っています。

では。