それぞれの定義
主にTask型を例にとって話す。
andThen : (a -> Task x b) -> Task x a -> Task x b
map : (a -> b) -> Task x a -> Task x b
考察
mapについて
手前味噌ではあるが、map関数の本質的な部分に関しては以前書いた以下の記事に詳しい。
>>> Elmのmap関数について一通りまとめてみた - @lilpacy | Qiita
andThenについて
Task以外の代表的な型について公式の説明を取り上げつつ説明を試みる。
andThen : (a -> Maybe b) -> Maybe a -> Maybe b
Maybe.andThen: Chain together many computations that may fail.
Maybe.andThen: 失敗する可能性のある多くの計算を連結します。
andThen : (a -> Result x b) -> Result x a -> Result x b
Result.andThen: Chain together a sequence of computations that may fail.
Result.andThen: 失敗する可能性のある一連の計算を連結します。
map
は大抵のプリミティブな型に存在しているが、andThen
は失敗する可能性を表現した型(Maybe,Result,Taskなど)にしか存在しないのが特徴的だった。
以上より、andThenは一般に、失敗する可能性のあるいくつかの処理をチェーン(して平坦化)するものだと解釈できそうだ。
両者の違い
2019.11.10 追記
以下にうだうだ書いているけれど、とどのつまり、map
とandThen
の違いは、データ構造に値を包んだまま内部の値を変換するか、値を包んだデータ構造から値を取り出して再度包み直すかと言って良さそうだと思った。
違いは第一引数にとる関数の構造が(a -> Task x b)
なのか(a -> b)
なのかだけではあるが、公式的には
Task.andThen:
Chain together a task and a callback.
The first task will run, and if it is successful,
you give the result to the callback resulting in another task.
This task then gets runTask.andThen:
タスクとコールバックを連結します。
最初のタスクが実行され、成功すると、
コールバックに結果が渡され、別のタスクが発生します。
次に、このタスクが実行されます。
とあるように、andThen
はコールバックをするため
Task.map: Transform a task.
Task.map: タスクを変換します。
map
は変換するためのものであると説明がなされている。
しかし、公式にはTask.succeed
の説明のところに、
Task.succeed:
A task that succeeds immediately when run. It is usually used with andThen.
You can use it like map if you want:Task.succeed:
実行するとすぐに成功するタスクで、通常andThenと共に使用されます。
それ(andThen)は必要に応じてmapのように使用できます。
とあるように、andThen
もmap
のようにラップされた値をラップされたまま変換するという使い方もできる。
以下、それぞれandThen
をmap
的に使った場合と、map
をandThen
的に使った場合の事例。
Process.sleep (60 * 60 * 1000)
|> Task.andThen (\_ -> Time.now)
|> Task.andThen (\t -> Task.succeed (Time.posixToMillis t))
Process.sleep (60 * 60 * 1000)
|> Task.map (\_ -> Time.millisToPosix 1572814010059)
|> Task.map (\t -> Time.posixToMillis t)
ちなみに、例が適切かどうかは不明。
まとめ
つまるところ、違いは第一引数に取る関数の構造の違いだけであるので、andThen
をmap
のように使うこともできるしmap
をandThen
のように使うこともできそうだ。
けれど、andThen
、map
という名前がつけられているだけにそれぞれをみだりに役割を変えて使うことは可読性という観点からは避けた方が無難であると感じた。
もっとも、Task.andThen
にはTaskの再帰をフラットにして処理をチェーンしていくという使い道の方が一般的みたいではあるが。
最後にTaskの再帰方法です。単に受け取った結果を元に再びAPIを叩くと、Task (Task Response)のような感じでTaskがネストしてしまいます。それをフラットにする関数がTask.andThenになります。再帰方法はCmdを利用したときと同じ形になります。最終結果は固定値をTask.succeedで返します。
>>> ElmでHttpをわかってしまおう - @ababup1192 | Qiita
以上。