[Elm]一覧のViewを自在に操る miyamoen/select-list

ヤギの人の[一覧のViewを自在に操る elm-reference](https://qiita.com/arowM/items/6eaadc5f43880e1f3787)を読んできてね

# 概要

- list viewでindexベースで要素を更新するのは煩雑
- Mutable なプログラミング言語の「参照」があれば解決する
- elm-referenceはthis(現在注目している値)とroot(大元の値)の概念を用いて値に注目しつつ元の値を復元することで解決する
- 今回提案するselect-listでも値に注目しつつ、大元の値（Listに限定）を復元することで解決する

[ということで 🎉🎉🎉I have just published miyamoen/select-list!🎉🎉🎉](https://package.elm-lang.org/packages/miyamoen/select-list/latest/)

# モチベーション

immutable data structureでtreeをいい感じに更新する[Zipper](https://en.wikipedia.org/wiki/Zipper_(data_structure))っていうものがあります
このselect-listはzipperのlist版です。

elm-referenceの差別化点としてはList特化なのでその分Listには使いやすい感じになってます（当者比

もちろん自分でも普段使いしてます。べんり（当者比

# `select-list`の基本操作

まずは型

```elm
type SelectList a
    = SelectList (List a) a (List a)
```

2個目の`a`の値が選択されている値（selected value）で、最初の`List a`が選択値の前のList（list before）、3個目の`List a`が選択値の後ろのList（list after）です

```elm
[ 1, 2, 3, 4, 5, 6, 7 ]
```
このリストを3を選択したSelectListに変換すると

```elm
([] :: 1 :: 2) 3 (4 :: 5 :: 6 :: 7 :: [])
```
こんな感じになります。`before`は内部的にひっくり返ってるのでひっくり返して表示してます

これのフォーカスを右（after）に2個動かすと

```elm
([] :: 1 :: 2 :: 3 :: 4) 5 (6 :: 7 :: [])
```
こんな感じになります。before/afterなlistの先頭をはいだり足したりしながら手繰り寄せる感じですね。内部の話なんで本題ではないんですがこんな仕組みになってます

# `select-list`をつかって書き直してみる

[一覧のViewを自在に操る elm-reference](https://qiita.com/arowM/items/6eaadc5f43880e1f3787)は読みましたか？読みましたよね？いきなり例出しますよ？

```elm
type Msg
    = ClickNumber (SelectList Int)


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        ClickNumber selectList ->
            ( { model
                | nums =
                    SelectList.toList <|
                        SelectList.updateSelected ((+) 1) selectList
              }
            , Cmd.none
            )


view : Model -> Html Msg
view model =
    div [] <| SelectList.selectedMapForList renderRow model.nums


renderRow : SelectList Int -> Html Msg
renderRow selected =
    div
        [ Events.onClick (ClickNumber selected) ]
        [ text <| String.fromInt <| SelectList.selected selected ]

```

`elm-reference`とほぼ一緒です。Msgに渡すものが`Reference Int (List Int)`から`SelectList Int`に代わったくらいです

そして一番大事な`SelectList.selectedMapForList`の型ですが

```elm
selectedMapForList : (SelectList a -> b) -> List a -> List b
```
比べてみましょう

```elm
selectedMapForList : (SelectList a   -> b) ->            List a    -> List b
unwrap :             (Reference  a x -> b) -> Reference (List a) x -> List b
indexedMap :         (Int ->     a   -> b) ->            List a    -> List b
```

`indexedMap`と比較するとindexの代わりに`SelectList a`を渡しています
`a`の値は渡していませんが`SelectList`が選択している値が`a`ということになります

また、型構造を上で見た通り全体の構造が分かるのでindexも取れます。まあふいんきでわかってもらえたと思うのであとはpackage document読んでください（型眺めてるほうがわかることない？）

# もっと比較したい場合は…

ここからふいんき度上がります。

`elm-reference`のほうがいい点

- `Reference (List a) x`のxで大本の構造まで一発で戻せそう
    - `select-list`ではlistまでしか戻せないので
- list以外にも使える抽象
    - exmapleにはtreeが用意されています
        - 一方わたしは[tree用のpackageも用意した](https://package.elm-lang.org/packages/miyamoen/tree-with-zipper/latest/)

`select-list`のほうがいい点

- List特化
    - indexとか他の要素へもアクセスできる
    - 選択している要素を上下に動かすとか要素の挿入とか削除とかのAPIを用意している
        - `elm-reference`の[example](https://github.com/arowM/elm-reference/blob/master/example/src/UpDown.elm)で上下移動と削除の例があるんですがちょっとわたしには実装が難しすぎました

結局自分で使うのにちょうどいいのを追求していく感じで作ってます

# 宣伝

[Elm-jp](https://discordapp.com/invite/m9Ew6fR)では公式ガイドの[翻訳活動](https://github.com/elm-jp/guide)をしています

深刻なレビュアー不足なので助けて