Elm の Task について私的まとめ

Elm の Task がよく分からなかったので、自分なりに調べて理解した点をメモしておきます。
公式の情報も少ないようなので最後は自分の言葉でまとめています。
間違いや変なところがあったら指摘ください。


## [基礎からわかるElm](http://www.c-r.com/book/detail/1299) の説明

P.150 より：

> **Task**は、非同期処理を行うための仕組みです。使い方はCmdとよく似ていますが、より複雑な処理を柔軟に行うことができます。

> Taskは、Resultの非同期バージョンともいえます。

:thinking: …？

「Task is コレ」な感じの説明を期待していたのですが、「コレ」にあたる部分がないように思いました。
強いて言えば「非同期処理を行うための仕組み」が「コレ」だと思いますが、どうにも抽象的で要領を得ません。


## Elm ガイドの説明

とりあえず Elm ガイドを頼ります。
Task についての記述は [Time のページ](https://guide.elm-lang.jp/effects/time.html) にあります。

> **Task.perform**
> 
> `Time.Zone`を取得するのはちょっと工夫が必要です。次のようなコマンドを発行しました：
>
> ```elm
> Task.perform AdjustTimeZone Time.here
> ```
>
> この行を理解するための最良の方法は、`Task`のドキュメントに一通り目を通すことです。そのドキュメントの中で、実際に`Task`という新しい概念について説明がなされています。ここで中途半端な説明をして脱線するのはやめようと思いますが、大事な点はランタイムシステムに対して、このコードの実行時に`Time.Zone`を返すように指示しているだけということです。

Elm ガイドにおける Task についての記述はこれが全文です。
Elm ガイドを見ても Task が何なのかよく分からない…。
「`Task` モジュールのドキュメントを見てね」ということなのでそちらを見ます。


## [Task モジュールのドキュメント](https://package.elm-lang.org/packages/elm/core/latest/Task) の説明

モジュールの概要と `Task` 型の説明を見ていきます。

モジュールの概要：

> Tasks make it easy to describe asynchronous operations that may fail, like HTTP requests or writing to a database.

- Task を使うと失敗する可能性のある非同期処理を簡単に書けるよ。

なるほど？ :thinking:

`Task` 型の説明：

> More generally a task is a *description* of what you need to do. Like a todo list. Or like a grocery list. Or like GitHub issues. So saying "the task is to tell me the current POSIX time" does not complete the task! You need `perform` tasks or `attempt` tasks.

- あるタスクは実施する必要のあることを記述したものだよ。
- 記述しただけではタスクは完了しないので `Task.perform` や `Task.attempt` で実行する必要があるよ。

Task は何らかの処理を指しており、`Task.perform` や `Task.attempt` を使って実行する、と判断しました。


## オレオレ Task 説明

Task についての公式の説明があまりないようなので、得られた情報から「つまりこういうことでは？」と思ったことをまとめます。

1. Elm アプリケーションの内側では、現在時刻取得のように副作用のある操作を実行できない。
2. Elm アプリケーションの外側 (Elm ランタイム) で目的の処理を実行し、その結果 (現在時刻等) を Msg でアプリケーションに伝えてもらう必要がある。
3. Elm ランタイムとしては処理がどのような内容 (現在時刻の取得だったり HTTP リクエストの送信だったり) でも一律同じ形式で扱いたいので、そのためのインターフェース [^1] として Task がある。  
4. Task を用意しただけでは駄目で、それを Elm ランタイムに伝える必要があるので Cmd を使用する。  
処理を Task にラップしてさらに Cmd にラップするイメージ。
5. 失敗しない Task については `Task.perform` 、失敗の可能性がある Task については `Task.attempt` で `Cmd` 型に変換し、Elm ランタイムへ投げる [^2] 。

[^1]: 言語仕様としてのインターフェースではなく、より広義のインターフェース。

[^2]: 特に意味はないが `Task.perform` を使うところで `Task.attempt` を使ってもよい。役割が異なるのではなく、特定の状況 (失敗がない場合) において `Task.attempt` をより簡潔に書けるのが `Task.perform` 、という位置付け。

「Task is コレ」については「Task は Elm ランタイム用のインターフェース (であり、目的の処理をラップしたもの) 」というのが 1つの回答になると考えています。~~非同期処理のことは気にするな。~~

**おしまり**


## 追記

Task と非同期処理について @ababup1192 さんに Twitter でフォローいただきました。
[ElmでHttpをわかってしまおう](https://qiita.com/ababup1192/items/b03fce202e1018bc4992) の記事は読んでいましたが本質的な部分を読み取れていなかったのは不覚… :cry:

<blockquote class="twitter-tweet" data-conversation="none" data-lang="ja"><p lang="ja" dir="ltr">最後に一言で言うと、で 非同期について気にするなとかいてありますが<br>まさに非同期を扱うための機構そのものです<br>HOWがランタイムとの交信ってだけで</p>&mdash; ABAB↑↓BA (@ababupdownba) <a href="https://twitter.com/ababupdownba/status/1125723580090802176?ref_src=twsrc%5Etfw">2019年5月7日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">例えば 起こしたい非同期処理が複数あって １つ目の結果を使って 直列に副作用を起こしたい<br>得たい結果は最後の非同期処理の結果だけだ<br>みたいなとき Cmdオンリーの場合 どんなつらみがあると思いますか？</p>&mdash; ABAB↑↓BA (@ababupdownba) <a href="https://twitter.com/ababupdownba/status/1125728428563415041?ref_src=twsrc%5Etfw">2019年5月7日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ですです。その途中状態が必要なのであれば必須ですが<br>わざわざ１つの処理に3つも4つもtmpな値を取っておくのは好ましくないのです。</p>&mdash; ABAB↑↓BA (@ababupdownba) <a href="https://twitter.com/ababupdownba/status/1125730408862085122?ref_src=twsrc%5Etfw">2019年5月7日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>