- Elm Advent Calendar 2016 - Adventar 9日目
- Elmの勉強の記録
- 今回は読書ノート
Compiler as Assistant
- Richard Feldman, Elm in Action MEAP V03, pp.55-87
学んだこと、目に留まった箇所
Elmではtype annotationはoptional
- 書かなくてもビルドできる
- Elm in Actionでも1章、2章のコードでは型定義は書いてなかった
-
elm-make
で--warn
オプションつけると、型推論によって型定義がサジェストされる
3章で取り上げると宣言してること
- スキップしてきた型定義
-
case
式 - データ型として、
Array
、Maybe
- union type
-
command
を使った乱数生成
on boadingコストを下げるツールとしての型定義
- coolでawesomeな言語で開発されたプロジェクト
- とてもよいこと。
- ソースコードへの信頼性は高い。テストも書かずに、ランタイムエラーの出ないアプリかける
- よいこと。
- awesomeで信頼性高いコードが書かれてるが、ドキュメントもテストもないし、コードはクリーンアップされてない
- リソースはコード書いて信頼性高いアプリかくことに全力投下してる
- こんな状態で新人が参加したらどうすべき?
- リソース限られた状況で、キャッチアップコストどうやって下げる
- ドキュメント?、テスト?、ソースの整理?
- 「最初に型定義」、これがrichardの答え
コメントは嘘が時々書かれてる。コードは嘘が書かれてない。型定義も同じ
- 書かれた当時は正確でhelpfulなコメントも半年後には正しくないコメントに変わってる可能性
- コメントがノイズになる
- 型定義はノイズにならない
- ビルドが通すことによって、書かれた型定義が正確であることが保証されてる
- 信頼できる情報源としての型定義
型定義の例
定数
-- 定数
urlPrefix: String
--関数
isEmpty : String -> Bool
isEmpty str = str == "”
List
とArray
の違い
-
List
- リテラルシンタックスあり
['hello', 'world', 'elm']
- メンバーアクセスは、最初のメンバーだけアクセス可能
- 任意の位置のメンバーへアクセスできない
- パフォーマンス性能よいので、
Array
ではなくList
をつかうべき
- リテラルシンタックスあり
-
Array
- 任意の順番のメンバーへアクセスできる
- 関数
Array.from
の戻り値としてArray
を作られる- qualifiedスタイルだと、
Array.Array.from
になるので、unqualifiedスタイル推奨 import Array exposing (Array)
- qualifiedスタイルだと、
- リテラルシンタックスがないので、
Array.from
などを使って生成する
型変数
この辺別エントリでかいた
「あとで書く」と予告されてる特別な型変数
number
appendable
comparable
型変数は小文字であれば何でもいいが、この3つだけはElmでは特別な意味を持つ、らしい
type alias
type alias
というキーワードつかう
TodoMVCのコードから例をとると、
type alias Model =
{ entries : List Entry
, field : String
, uid : Int
, visibility : String
}
type alias Entry =
{ description : String
, completed : Bool
, editing : Bool
, id : Int
}
- 同じ型定義を繰り返し書くのを回避
- 修正箇所が1箇所になり、メンテしやすさUP
Html
の型変数
view : Model -> Html Msg
view model =
...skip
-
view
関数の戻り値がHtml
ではないのはなぜか?-
Html
がupdate
関数に送るメッセージを表現してる -
msg
の型は、ハンドラが送るメッセージの型によって決まる -
onClick
が送るメッセージの型、とか
-
div [ onClick { x = 3.3 } ] []
- これだと{ x = 3.3 }
というメッセージをHtmlが送っている、という意味
type alias Msg =
{ operation : String, data : String }
view : Model -> Html Msg
複数の引数をとる関数の型定義
別エントリで書いた
Elmでは関数の戻り値は1つだけで引数も1つだけ
case
式の話
- jsの
if..else
文と比較してるところがわかりやすい
_ ->
model
-
これがjsの
else
節、switch
文のdefault...
に近い -
アンダースコア
_
は、作法でなのか、Elmの文法上の理由なのかが、まだわからない- 要調べる
-
case
式はマッチしたらそこで評価が終わる- これがjsと違うとこ
case
式とunion typesを組み合わせる
- 通常コードではこっちのパターンが多い
- 利点は、
_ ->...
というブランチを消せる点 -
case size of ...
というコードで、size
がString
であれば、FETACH_DATA
やPOST_DATA
とか想定してるString
に処理を書くだけで終わらず、「それ以外のString
が来た場合」をかかないといけない - でも
size
がunion typeであれば、可能性は列挙されててるので、「それ以外」が存在しない型定義
type PhotoSize = XS| LL | XL
というunion typeをcase
式に渡せば、ありうる可能性はXS
かLL
かXL
だけになる
XL
のケースとか書き忘れてると、コンパイラがちゃんとビルド時に警告出すのも便利
“-- MISSING PATTERNS -------------------------------- PhotoGroove.elm
This `case` does not have branches for all possibilities.
...
You need to account for the following values:
PhotoGroove.SetSize _
Add a branch to cover this pattern!”
Excerpt From: Richard Feldman. “Elm in Action MEAP V03.” iBooks.
このunion typeの図がよかった
-
XS
はtype constructor
です、と言えることがわかったので - いつも何て呼べばいいのか困ってた。タグ?、値の1つ?という有様だったので
Maybe
型
自分の理解がふわっとしてる箇所
type Maybe value
= Just value
| Nothing
- 値がない可能性を表現するデータ型
- jsの
null
やundefined
のようなケースをElmではどう扱っているのか、という部分
戻り値がMaybe a
型であるArray.get
を使って説明してる
get : Int -> Array a -> Maybe a
-
Array
のメンバーを取り出すための関数- 型変数は
a
は何でもよい - が、
Array
とMaybe
で同じになってることで、Arrayのメンバーと取り出せる値が同じ型であることが保証
- 型変数は
-
メンバーのインデックスがArrayにはない可能性
-
渡されたArrayが空である可能性
という可能性のときに、Array.get..
を評価した結果、Nothing
を返す。
getPhotoUrl : Int -> String
getPhotoUrl index =
case Array.get index photoArray of
Just photo ->
photo.url
Nothing ->
""
のように使う時は、case
式を使って可能性を列挙してどうするかを記述する必要がでてくる
- 書かないと、コンパイルが通らない
-
Maybe a
が戻り値である関数を使う時は、case
式使うのが必須- 可能性を列挙するように書かざるをえない
- Elmの「値が無い可能性」に対するアプローチ、ということか
- ということがわかった
Random
モジュール使って、ランダムにArray
からメンバーとってくる
別エントリにかいた