LoginSignup
11
4

More than 3 years have passed since last update.

[Elm] andThenとmapの違いについて

Last updated at Posted at 2019-11-04

それぞれの定義

主に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以外の代表的な型について公式の説明を取り上げつつ説明を試みる。

Maybe
andThen : (a -> Maybe b) -> Maybe a -> Maybe b

Maybe.andThen: Chain together many computations that may fail.
Maybe.andThen: 失敗する可能性のある多くの計算を連結します。

Result
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 追記

以下にうだうだ書いているけれど、とどのつまり、mapandThenの違いは、データ構造に値を包んだまま内部の値を変換するか、値を包んだデータ構造から値を取り出して再度包み直すかと言って良さそうだと思った。


違いは第一引数にとる関数の構造が(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 run

Task.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のように使用できます。

とあるように、andThenmapのようにラップされた値をラップされたまま変換するという使い方もできる。

以下、それぞれandThenmap的に使った場合と、mapandThen的に使った場合の事例。

andThenをmap的に(ラップされた値の変換として)
Process.sleep (60 * 60 * 1000)
    |> Task.andThen (\_ -> Time.now)
    |> Task.andThen (\t -> Task.succeed (Time.posixToMillis t))
mapをandThen的に(コールバックのつなぎとして)
Process.sleep (60 * 60 * 1000)
    |> Task.map (\_ -> Time.millisToPosix 1572814010059)
    |> Task.map (\t -> Time.posixToMillis t)

ちなみに、例が適切かどうかは不明。

まとめ

つまるところ、違いは第一引数に取る関数の構造の違いだけであるので、andThenmapのように使うこともできるしmapandThenのように使うこともできそうだ。

けれど、andThenmapという名前がつけられているだけにそれぞれをみだりに役割を変えて使うことは可読性という観点からは避けた方が無難であると感じた。

もっとも、Task.andThenにはTaskの再帰をフラットにして処理をチェーンしていくという使い道の方が一般的みたいではあるが。

最後にTaskの再帰方法です。単に受け取った結果を元に再びAPIを叩くと、Task (Task Response)のような感じでTaskがネストしてしまいます。それをフラットにする関数がTask.andThenになります。再帰方法はCmdを利用したときと同じ形になります。最終結果は固定値をTask.succeedで返します。

>>> ElmでHttpをわかってしまおう - @ababup1192 | Qiita

以上。

11
4
2

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
11
4