[Elm] Attributes.batch で Attributes をもっと柔軟に使いこなそう

ElmでViewの共通化をしたいとき、別にViewを頑張ってつくらなくてもAttributeを"Mixin"として使い回せばいいことがわりとあります。

たとえば

```elm
module Mixin exposing (..)

import Html exposing (Attribute)
import Html.Attributes as Attributes

bigButton : Attribute msg
bigButton =
    Attributes.class "button button_big"
```

のような関数を定義して使いまわすイメージです。

この例は簡単なので別にこれでもいいんですが、場合によっては複数の Attribute をセットにして使いまわしたいことがしばしばあります。

```elm
module Mixin exposing (..)

import Html exposing (Attribute)
import Html.Attributes as Attributes

submitButton : Bool -> List (Attribute msg)
submitButton sending =
    [ Attributes.class "button"
    , Attributes.class "button_submit"
    , Attributes.disabled sending
    ]
```

このようにリストにするだけなのですが、これをViewで呼ぼうとするとどうなるでしょうか？


```elm
module Main exposing (..)

import Html exposing (Html)
import Html.Attributes as Attributes
import Mixin

submitButton : Model -> Html msg
submitButton model =
    Html.button
        (Mixin.submitButton model.sending)
        []
```

これを見る限りは特に問題なさそうですね！

じゃあ、`Mixin.bigButton` と `Mixin.submitButton` を同時に使いたい時はどうなるでしょうか？

```elm
bigSubmitButton : Model -> Html msg
bigSubmitButton model =
    Html.button
        ( Mixin.bigButton :: Mixin.submitButton model.sending)
        []
```

ちょっと嫌な予感がしてきましたね？

じゃあ、ピンク色の大きな送信ボタンを作ろうと思ったらどうなるでしょうか？
ピンク色のボタンにするための Mixin が以下の型をしているとします。

```elm
pinkButton : List (Attribute msg)
```

こうなりますね？

```elm
bigPinkSubmitButton : Model -> Html msg
bigPinkSubmitButton model =
    Html.button
        ( Mixin.bigButton :: Mixin.submitButton model.sending ++ Mixin.pinkButton)
        []
```

わーお。

それじゃあ今度は、`model.broken` が `True` のときのみ `class="broken"` を付けてボタンがぶっ壊れるようにしてみましょう！

```elm
bigPinkHotSubmitButton : Model -> Html msg
bigPinkHotSubmitButton model =
    Html.button
        (Mixin.bigButton
            :: Mixin.submitButton model.sending
            ++ Mixin.pinkButton
            ++ (if model.broken then
                    [ Attributes.class "broken"
                    ]

                else
                    []
               )
        )
        []
```

うぅううううううああああああああ！！！！！
もういやだぁあああああああああ！！！！！！！！！！
おうちにかえるぅうううううううう！！！！！！！！！！！

![sakuraaaaa.jpeg](https://qiita-image-store.s3.amazonaws.com/0/16345/36a45a5e-cebd-b806-76c0-b766a5614160.jpeg)

## 追記 2019/8/11

最近は [elm-mixin](https://package.elm-lang.org/packages/arowM/elm-mixin/latest/) というライブラリを作ったので、そちらをメインに使っています。

## Attributes.batch で解決する


たとえばこれを以下のように書けるとしたらいかがでしょうか？


```elm
module Mixin exposing (..)

...
...

submitButton : Bool -> Attribute msg
submitButton sending =
    Attributes.batch
        [ Attributes.class "button"
        , Attributes.class "button_submit"
        , Attributes.disabled sending
        ]

pinkButton : Attribute msg
pinkButton =
    Attributes.batch
        [ ...
        , ...
        ]
```

```elm
module Main exposing (..)

...
...

bigPinkHotSubmitButton : Model -> Html msg
bigPinkHotSubmitButton model =
    Html.button
        [ Mixin.bigButton
        , Mixin.submitButton model.sending
        , Mixin.pinkButton
        , if model.broken then
            Attributes.class "broken"

          else
            Attributes.none
        ]
        []
```

めちゃくちゃ可読性が向上してませんか？

これを実現する上でポイントとなっているのが次の2つの関数です。

```elm
Html.Attributes.batch : List (Attribute msg) -> Attribute msg

Html.Attributes.none : Attribute msg
```

ちょうど `Cmd` とか `Sub` とかの `Cmd.batch` `Cmd.none` と似たイメージですね！

## arowM/html

さて、便利さはわかりましたが、残念ながらこれらの関数は `elm/html` にも `elm-community/html-extra` にも含まれていません。
これらを使うには [arowM/html](https://package.elm-lang.org/packages/arowM/html/latest/) に **乗り換える** 必要があります。

詳細は省きますが、`elm/html` に **加えて** 他のライブラリを読み込む形では `Html.Attributes.batch` のようなものは実現できません。
そこで、`arowM/html` は `elm/html` を **置き換える** という戦略をとっています。

もちろん互換性は保ってありますので、今まで書いてきた `elm/html` に依存したコードは `arowM/html` に乗り換えてもそのまま同じように動きます。
それに加えて、上記の `batch` と `none` が使えるようになるのです。

## arowM/html への置き換え方

`elm/html` にさよならして `arowM/html` に置き換えるのはとても簡単です。

1. `elm.json` の dependencies にある `elm/html` を `arowM/html` に変える
2. elm-stuff ディレクトリを削除する
3. コンパイルしなおす
4. コンパイラが「こいつらを `elm.json` の "indirect" に追加してね」と教えてくれるので指示にしたがう

これだけでコンパイルが通るようになり、`batch` や `none` の力が手に入ります！

[さくらちゃんにご飯をあげる](https://www.amazon.co.jp/gp/registry/wishlist/20ZV2VC57615B/ref=nav_wishlist_lists_1)
[さくらちゃんをもっと見る](https://twitter.com/hashtag/%E3%81%95%E3%81%8F%E3%82%89%E3%81%A1%E3%82%83%E3%82%93%E6%97%A5%E8%A8%98?src=hash)
[他の記事を見る](https://qiita.com/arowM)
![sakura.jpeg](https://qiita-image-store.s3.amazonaws.com/0/16345/a08e5988-e3d9-c4f6-d01b-b8055ce8bb6a.jpeg)