TODOリストを作る部 その1

日本人の朝食といえば白米
犬といえば柴犬
日本の山といえば富士山
プログラミング言語の学習といえば…?
そうだね、TODOリストだね

なのでTODOリスト作ります

ellie-app.com

やること

  • [x] ListでTODOリストを保持する
  • [x] ListHTMLに吐き出す
  • [x] inputに入力した値をbuttonを押すことでリストに追加
  • [ ] 無名関数の関数化
    せっかくだからやったほうが良いと思う
  • [ ] 空のTODOは追加できないようにする
  • [ ] TODO横に削除ボタンを作成、押したら消せるように
  • [ ] TODOをダブルクリックでinput化して更新できるように
  • [ ] localstorageに保存できるようにする
  • [ ] 見た目オシャンティーにする

やったこと

ベースとなるレコードの定義

type alias Model =
    { todoList : List String 
    , inputText : String
    }


initialModel : Model
initialModel =
    { todoList = [ "a", "b", "c" ]
    , inputText = ""
    }

type alias Model

  • todoList
    表示するTODOの一覧
    追加、削除、更新されたりする
    これを参照してTODOを表示するようにする
  • inputText
    追加用のinputの内容を受け取る
    TODOリストの追加に使う

initialModel

初期化しているだけ
適当なTODOリスト表示用のデータと空の入力欄データを用意

動作(Msg)の定義

type Msg
    = Add
    | UpdateTextField String
  • Add
    TODOの追加
    inputTextをそのままtodoListに追加するつもりなので引数なし
  • UpdateTextField String
    inputTextの更新
    onInputからStringの引数で入力値が渡ってくる

update

update : Msg -> Model -> Model
update msg model =
    case msg of
        Add ->
            { model | todoList = model.inputText :: model.todoList }

        UpdateTextField txt ->
            { model | inputText = txt }

Add

追加ボタンを押したタイミングでinputTextに入っている値を
TODOListに追加している
todoList = model.inputText :: model.todoList
model.inputText :: ["a", "b", "c"]で配列の先頭に追加して
それをtodoListに代入している 他言語だと大体末尾に追加するから何だか新鮮 docs/syntax

UpdateTextField

inputTextをフィールドの値で更新している
onInputなので入力する度に発火している
物凄いイベント量だけどonBlurとかのほうがいいのかな?と思っている

showTodoList

showTodoList : List String -> Html msg
showTodoList todoList =
    todoList
        |> List.map (\todo -> li [] [ text todo ])
        |> ul []

今回の目玉。todoListを使って以下のリストを作る

<ul>
  <li>a</li>
  <li>b</li>
  <li>c</li>
</ul>

引数はString型のListで戻り値はHtml msg
戻り地をそのままviewに渡してHTMLが描画できる

|>

パイプ演算子
左から右に流れるので感覚的に慣れていて読みやすい(LInux|っぽい)
js[1,2,3].map(val => val * 1);みたいな関数っぽく読める
docs/syntax

|> List.map (\todo -> li [] [ text todo ])

List.map関数でtodoList内のデータに対して
無名関数(\todo -> li [] [ text todo ])を1つずつ適用する
\から始めると無名関数が作れて()で無名関数の範囲を指定できる
以下のようなListが生まれる

[ li [ text "a" ]
, li [ text "b" ]
, li [ text "c" ]
]

|> ul []

ul []の後ろに上で作ったliの塊をくっつける
するとこうなる

ul []
    [ li [ text "a" ]
    , li [ text "b" ]
    , li [ text "c" ]
    ]

見覚えのある形
そう、Htmlモジュール全部触ろうで散々書いたHtmlのタグの形である

view

, showTodoList model.todoList

先程作ったul [] [ li [] [] ]を作るshowTodoListを読んでいる
showTodoListの引数はList StringなのでTODOリストの元となる
model.todoListを渡している

まとめ

  • パイプ演算子が全く慣れない
    関数全くわからん さっぱりだ
    でも面白い。もっと理解してゴリゴリ書けるようになりたい
  • 間違いをコンパイラが丁寧に全部教えてくれた
    • 関数の引数と型あってないぞ!
    • List (Html msg)じゃなくてHtml Msgくれ! などなど。学習の手助けをひたすら健気にしてくれてありがたい
  • ネットに転がってるサンプルの質が高い(気がする)
    javaScriptだとググったらすぐ出るんだけど、レガシーだったり変なコードだったりすることが多々ある
    Elmは不思議とそういうコードに今のところであってない気がする
    (無知で良いコードと悪いコードの区別がついていない説もある)

おまけ

List StringからHtmlに変換するとこ

stackoverflow.com
ググったらこんなのが出てきて混乱した

renderList : List String -> Html msg
renderList lst =
    ul []
        (List.map (\l -> li [] [ text l ]) lst)
renderList : List String -> Html msg
renderList lst =
    lst
       |> List.map (\l -> li [] [ text l ])
       |> ul []
renderList : List String -> Html msg
renderList lst =
    lst
       |> List.map (li [] << List.singleton << text)
       |> ul []

パイプ演算子しかわからない
ぜんぜんわからない 俺たちは雰囲気でElmをやっている
f:id:nekorollykk:20200825012126p:plain

\

\λっぽいって話がガイドに書いてあった
言語の基礎 · An Introduction to Elm
バール片手に暴れまわる物理学者を思い出しました
HALF-LIFE3まだ?
f:id:nekorollykk:20200825011510p:plain