LoginSignup
7
7

More than 5 years have passed since last update.

ElmのStartApp.Simpleの仕組み

Last updated at Posted at 2015-10-04

追記
この記事は古いです。過去のものです。忘れましょう

対象読者

Elmを勉強しようと思って公式のドキュメント読んででelm-architecture-tutorialを見てどういう仕組みだよこれってなった人(つまり私)
コードとかは上記チュートリアルとライブラリからの引用。内容としてはライブラリのコードを追っかけて理解できたことをまとめている。javascriptまでは踏み込んでない

こんなバージョン。0.15.1

elm-package.json
"dependencies": {
    "elm-lang/core": "2.1.0 <= v < 3.0.0",
    "evancz/start-app": "2.0.1 <= v < 3.0.0"
},
"elm-version": "0.15.1 <= v < 0.16.0"

全体を見る

Main.elm
import Html exposing (div, button, text)
import Html.Events exposing (onClick)
import StartApp.Simple as StartApp

main =
  StartApp.start { model = model, view = view, update = update }

model = 0

view address model =
  div []
    [ button [ onClick address Decrement ] [ text "-" ]
    , div [] [ text (toString model) ]
    , button [ onClick address Increment ] [ text "+" ]
    ]

type Action = Increment | Decrement

update action model =
  case action of
    Increment -> model + 1
    Decrement -> model - 1

modelとviewとupdateを用意してStartApp.Simple.startにかませればあとはよしなにやってくれるらしい……

Addressを理解する

上記view関数の引数にaddressが登場してます。チュートリアルをみるとviewの型はview : Signal.Address Action -> Model -> Htmlで引数addressの型はSignal.Address Actionです。

このAddress型はSignal.elmで定義されています

Signal.elm
type alias Mailbox a =
    { address : Address a
    , signal : Signal a
    }
type Address a =
    Address (a -> Task () ())

Address型はMailbox型とセットです。Mailboxは関数Signal.mailbox : a -> Mailbox aで作ります。中にはaddresssignalが入っています。
この中のaddressに向かってMessage(a型の値)を送るとsignalが更新されます。

view関数で使われているaddressの正体はこの型です。型はAddress ActionなのでStartApp.Simple.startの中では、Mailbox Action型の値があってそこからSignal Actionを取り出して使っているんでしょう。(実際は少し違います)

StartApp.Simpleの実装

短くてsimpleです

Simple.elm
type alias Config model action =
    { model : model
    , view : Address action -> model -> Html
    , update : action -> model -> model
    }
start : Config model action -> Signal Html
start config =
  let
    actions =
      Signal.mailbox Nothing

    address =
      Signal.forwardTo actions.address Just

    model =
      Signal.foldp
        (\(Just action) model -> config.update action model)
        config.model
        actions.signal
  in
    Signal.map (config.view address) model

Config型が引数として渡している{ model = model, view = view, update = update }の型です。start関数はActionmailboxを作ってそこからActionを取り出してSignal Modelを作りview関数にmapしてます。

forwardTo

そしてチュートリアルの2にもあるSignal.forwardTo関数を使ってます。mailboxの型は正確にはMailbox Maybe aです。addressにはActionを送るのでそのままActionが送れる型にaddressを変えておく必要があります。

forwardTo : Address b -> (a -> b) -> Address a
forwardTo (Address send) f =
    Address (\x -> send (f x))

(a -> b)を使って渡されたaの型を変換しています。Signal.forwardTo actions.address Justではjustが使われています。
どうやらJust DecrementMaybe Action型となるのでJusta -> Maybe a型になるようです。

forwardToでできたaddressActionを送ることでmailboxが更新されるようになりました。
実際にaddressActionを送っているのはonClick関数などです。

最後に

こうしてみるとStartApp.SimpleMailBoxを中心とした薄めのラッパーという感じがします。ちょっとした仕組みでフレームワークみたいなものを実現していて驚きました。
Elmは日本語情報少ないので困りましたが結局コード読んでたら何とかわかりました。
せっかくなのでまとめてみました。学習の手助けになれば幸いです。

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7