今回は、この本の5.10から進める。
5.10はパターンマッチ。
パターンマッチはRustにもあるし、最近はRubyにも入ったけど、しっかり理解出来たとは言えない。 よく使うイディオムは書けるんだけど、それがどういう仕組みで動いているのかがよくわからない。 例えば、構造でマッチするパターンと、値でマッチするパターンがあって、それが組み合わされたりするけど、 あーゆーのをどういうルールで処理系が理解しているのかって、しっくりは来ていない。
だけど、まずはいろんな言語でいろんな本を読んでみる(そうして、帰納的な理解を深める)しかなかろうと思ってるので、今回もやっていく。
ここで紹介されているパターンは以下。他にもまだまだあるよとのこと。うーむ。
- タプルパターン
- 定数パターン
- 変数パターン
- ワイルドカードパターン
- ORパターン
- asパターン
ORパターンはパターンを並べる|
とmatch式の|
で同じ記号を使っているのが面白いと思う。これは好きかも。
> let f c = - match c with - | 'a' | 'i' | 'u' | 'e' | 'o' -> "Japanese Vowels" - | _ -> "Others";; val f: c: char -> string > f 'a';; val it: string = "Japanese Vowels" > f 'b';; val it: string = "Others"
さて、続きだ
- function式
- 引数を1つだけ取って、その引数に対してmatchさせる関数
- レコード(type)
- レコードに対する型推論は(フィールドの型ではなく)フィールド名を使って行われる
- レコードパターン
レコードのコピーと更新はこんな感じで出来る。普通に作るとレコードはimmutableなので、更新と言っても新しいのが出来る奴ね。
> type Player = { Name: string; Job: string; Level: int};; type Player = { Name: string Job: string Level: int } > let p1 = { Name = "Bill"; Job = "Wizard"; Level = 5};; val p1: Player = { Name = "Bill" Job = "Wizard" Level = 5 } > let p2 = { p1 with Job = "Knight"; Level = p1.Level + 1};; val p2: Player = { Name = "Bill" Job = "Knight" Level = 6 }
フィールドをmutableにすることも出来る。もちろん、望ましくはない。
> type Player = {Name: string; mutable Job: string; mutable Level: int};; type Player = { Name: string mutable Job: string mutable Level: int } > let p1 = {Name = "Bill"; Job = "Wizard"; Level = 5};; val p1: Player = { Name = "Bill" Job = "Wizard" Level = 5 } > p1.Job <- "Knight";; val it: unit = () > p1.Level <- p1.Level + 1;; val it: unit = () > p1;; val it: Player = { Name = "Bill" Job = "Knight" Level = 6 }
- 判別共用体(discriminated union, DU)
リテラルパターンの例はこんな感じ
> [<Literal>] - let Paranoia = "F#";; [<Literal>] val Paranoia: string = "F#" > "F#" |> function Paranoia -> "STAY GOLD" | _ -> "STAY AWAY";; val it: string = "STAY GOLD"
- 構造的な型と比較
- ここまで説明したのは全部構造的な型で、構造的な型の大小は、要素の定義順に比較して行われる
- option型
- ジェネリクス
- 型パラメータの書き方は、OCamlスタイルと.NETスタイルがあるが、.NETスタイルがオススメ
- 測定単位
- これも、ジェネリックにすることができる
単位を付けられるのは面白い。物理屋はよく式が正しいことを次元でチェックするけど、あれみたいなことですな。
- ボクシング
box
関数でボクシングすると、obj型になる:?
演算子で型チェックできる- :?パターン
- 例外
- failwithでSystem.Exception型の例外を投げられる。failwithfは引数にprintfフォーマットを使える
- ユーザー定義の例外はexceptionで定義して、raiseで投げる
- try...withでキャッチする。例外を投げ直すときはreraiseする。raiseするとスタックトレースが途切れる
これで5章は終わり