Msgを連続でupdateに流したい

# これなに
- updateを連続で作用させて「Msg1の後Msg2、その後...」みたいなことしたい
- とりあえず2種類くらいやり方があったので自分用に記録

## はじめに
ElmはupdateでMsgを呼ぶことでModelを更新してviewに反映していくのですが、ある処理の間にSleepを挟みたかったり、Msg一つとするには意味のまとまりが大きすぎたりするときにMsgで行う処理を分割して、Msg1の後Msg2を呼ぶ、みたいに続けてMsgを処理したい時が（個人的には）あります。

色々と調べたところ、2種類ほどやり方がありそうだったのでメモがわりにここに残しておきます。
なお、今回の例としてはElmのチュートリアルとして有名な、数字をIncrement/Decrementして増減させるコード（[Ellieで最初に見るコード](https://ellie-app.com/new)でもあります）を使用します。
注目するのは下のupdate部分です。

```elm
update : Msg -> Model -> Model
update msg model =
    case msg of
        Increment ->
            { model | count = model.count + 1 }

        Decrement ->
            { model | count = model.count - 1 }
```

## やり方1: まんまupdateを呼ぶ
Msgの処理でupdate関数を呼んで別のMsgを処理します。なんでこれ思いつかなかったんだ。

```diff
update : Msg -> Model -> Model
update msg model =
    case msg of
        Increment ->
-           { model | count = model.count + 1 }
+           update Decrement { model | count = model.count + 1 }

        Decrement ->
            { model | count = model.count - 1 }
```

こうするとボタンを押してIncrementが発出されたときにcountに+1されたModelができるのですが、それが続けてDecrementに送られるので-1されて、結局なにも起きません。虚無。

ちなみに下のようにすると…。

```diff:やばい
update : Msg -> Model -> Model
update msg model =
    case msg of
        Increment ->
-           { model | count = model.count + 1 }
+           update Increment { model | count = model.count + 1 }

        Decrement ->
            { model | count = model.count - 1 }
```

無限ループって怖くね？（Elmだったらこういうコードもコンパイルエラーになるかな？と思ったが流石にならなかった。）

## やり方2: Taskを使用する
本来は非同期処理のもの？とかElm Runtimeにお願いするもの？とか言われているけどやっぱり掴みどころのないTaskちゃんを使用します。Taskの詳しい説明は[先人の解説](https://qiita.com/ababup1192/items/008c0adac797d90c1dff)や[リファレンス](https://package.elm-lang.org/packages/elm/core/latest/Task)を参照してください。
下準備として、Cmd Msgを受け入れられるように、updateとmainを修正します。

```elm:update
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
    case msg of
        Increment ->
            ({ model | count = model.count + 1 }, Cmd.none)

        Decrement ->
            ({ model | count = model.count - 1 }, Cmd.none)
```

```elm:main
main : Program () Model Msg
main =
    Browser.element
        { init = always (initialModel, Cmd.none)
        , view = view
        , update = update
        , subscriptions = always Sub.none
        }
```

あと、`import Task`でTaskを使用できるようにしておきます。

今回はTask.performを使用します。これはまず失敗しないTaskについて使用するもので、今回はただ連続でMsgを処理するためこれを使用します。

```diff:update
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
    case msg of
        Increment ->
-            ({ model | count = model.count + 1 }, Cmd.none)
+            ({ model | count = model.count + 1 }, Task.perform (always Decrement) (Task.succeed ()))

        Decrement ->
            ({ model | count = model.count - 1 }, Cmd.none)
```

このようにすると、またIncrementの後にDecrementが呼び出され、数値は変わらずに虚無が再現されます。
解説すると、Task.performは下のような型を必要とする関数です。

```elm
perform : (a -> msg) -> Task Never a -> Cmd msg
```

最初の`(a -> msg)`部分で、連続して呼びたいMsgを与えればいいのですが、そのまま`Decrement`を与えてもコンパイルエラーになってしまいます。こういったときに便利なのがalwaysです。

```elm
always : a -> b -> a
```

常にaを出す関数と考えればいいんですかね（低理解度）。ともかく、これでMsgを送れます。

最後の`Task.succeed ()`ですが、`Decrement`の前にしたい処理もなく、また`Decrement`が必要とする引数もないので、無を渡すような処理になっています。例えば、ここに`Process.sleep 1000`などとすることで、数字が1増えた1秒後に数字が1減って元に戻るなどといった、まるで[世界で一番役に立たない機械](https://www.google.com/search?rls=en&sxsrf=ALeKk00gJnWxqENP9jQleuzocsptwZU4mw:1595750922706&source=univ&tbm=isch&q=Useless+box&client=safari&sa=X&ved=2ahUKEwjYg5e3u-rqAhUHVN4KHYR4BOcQsAR6BAgFEAE)のような動作が実現できます。

## まとめ
自分が調べた範囲では上の2種類の方法が有用そうでしたが、他にやりようが色々あるかなと感じます。特に処理を挟むことなくそのままMsgを連続で処理したいときは最初のやり方、間にSleepなどの処理を挟んだり、Elmの外の世界からTime.nowなどの数値を持っていきたいときは2番目のやり方で処理すればいいかなと思っています。

なんかいいベストプラクティスはないんだろうか…。