Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

それぞれの定義

主に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

以上。

lilpacy
ダンスとサブカルが好きなエンジニアです👾
https://portfolio.lilpacy.now.sh
fringe81
Fringeは、最新のテクノロジーとプロフェッショナルによるサービスにより、社会課題に仮説を立てて市場に広げていくことで、数十年という長期的なスパンで価値を生み出し続け、より良い世界を創る集団です。 既存の領域に限らず、時流を読み、仮説を生み出し、テクノロジーの力で優れたサービスを生み出し続けます。
https://www.fringe81.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away