Elmでは非同期処理を行うのにTaskというものを使うようなので試してみました。0.18の公式のドキュメントサイトにはまだ準備できていない旨のコメントがありましたので、以下のサイトを参考にさせていただきました。
https://giisyu.gitbooks.io/elm_usui_book/content/src/module/task.html
プログラムは開始時に「開始!」と表示し、5000ms後に「完了!」と表示します。それだけです。JavaScriptで言えば、setTimeout()に相当するsleep 関数を使います。以下に詳しい説明を加えていきます。
import Html exposing (Html, div, text)
import Html.Attributes
import Process exposing (..)
import Task exposing (..)
-- MODEL
type alias Model = String
type Msg
= TaskResult String
longTask : Task Never String
longTask =
Process.sleep 5000
|> Task.map (always "完了!")
init : ( Model , Cmd Msg)
init =
"開始!" ! [ Task.perform TaskResult longTask ]
update : Msg -> Model -> (Model,Cmd Msg)
update msg model =
case msg of
TaskResult str -> (str, Cmd.none)
view : Model -> Html Msg
view model =
text model
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
main : Program Never Model Msg
main =
Html.program { init = init, view = view, update = update, subscriptions = subscriptions }
ここで使うModelはStringそのものです。
type alias Model = String
Taskの実行結果は以下のMsgを発生し、updateを呼びます。
type Msg
= TaskResult String
次にTaskを作ります。
longTask : Task Never String
longTask =
Process.sleep 5000
|> Task.map (always "完了!")
まずTask型は以下のように定義されています。Taskコンストラクタに、エラーを表すerr値と、成功を表すok値が続きます。
type alias Task err ok = Task err ok
さてsleepの型は以下のように定義されています。Timeで指定した時間が経過した後に、Task x () が返ります。今回のTaskのテーマに関して言えば、ここが本質ですね。
Process.sleep : Time -> Task x ()
a |> f は f a のことですから、上のTaskの結果は Task.map (always "完了!") (Task x ()) のようになり、以下のmapの定義から Task x "完了!" になります。(always "完了!")関数は引数に()を取り 関数値は常に "完了!" になるからです。
Task.map : (a -> b) -> Task x a -> Task x b
always : a -> b -> a
以上の考察により、最終的に以下のような結果が得られます。
longTask = Task x "完了!"
次のinit関数を見ます。
init : ( Model , Cmd Msg)
init =
"開始!" ! [ Task.perform TaskResult longTask ]
これは ! の定義により以下と同等です。
init : ( Model , Cmd Msg)
init =
("開始!", Cmd.batch [ Task.perform TaskResult longTask ])
Task.performは以下のようにCmdを作り出します。Taskに実行結果の「Task x "完了!"」の"完了!"に第一引数のTaskResultを被せて、TaskResult "完了!" というMsgでupdateを呼びます。
Task.perform : (a -> msg) -> Task Never a -> Cmd msg
型を追うことでプログラムの理解が深まることがありますが、木を見て森が見えない罠に陥ることは避けたいですね。
Taskはどうなんだろう。Http.getも0.17のころはTaskだったのに、0.18ではRequestになっているし、公式ドキュメントでもまだ扱われていないし...