LoginSignup
9
2

More than 5 years have passed since last update.

ElmのTaskを試してみる

Last updated at Posted at 2017-12-23

 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になっているし、公式ドキュメントでもまだ扱われていないし...

9
2
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
9
2