ふつける 7 章
ふつける 7 章 p.160
Haskell には一行コメントがある。OCaml にも欲しい。Camlp4 使ったらできるんだろうか…。マクロとかプリプロセッサとか使うとエディタの色分けがおかしくなるから嫌なんだよな。逆にエディタがマクロの定義を解釈して色分けしたらいいかもしれない。
ブロック形式のコメントは {- -} で囲む。あまり見慣れぬ形式だ。ところで OCaml の (* *) は Pascal 由来なんだろうか。* が先頭にくる演算子を定義するときにうるさい。
リテレイト形式。使わん。
オフサイドルール。OCaml でも採用したら便利だろうか。for や while は do と done で ブロックの範囲を明示しているから 関係ない。実際にブロックの範囲が問題となるのはパターンマッチングがネストした場合である。
let rec string_of_sexp sexp = match sexp with Sexp_atom atom -> match atom with Atom_int v -> string_of_int v | Atom_string v -> v | Atom_float v -> string_of_float v | Sexp_list list -> let slist = List.map string_of_sexp list in sprintf "[%s]" (String.concat "," slist)
という関数をみると Sexp_atom と Sexp_list が並列のように見えるが、実は
let rec string_of_sexp sexp = match sexp with Sexp_atom atom -> ( match atom with Atom_int v -> string_of_int v | Atom_string v -> v | Atom_float v -> string_of_float v | Sexp_list list -> let slist = List.map string_of_sexp list in sprintf "[%s]" (String.concat "," slist) )
と解釈される。こんな時は begin .. end を使って、
let rec string_of_sexp sexp = match sexp with Sexp_atom atom -> begin match atom with Atom_int v -> string_of_int v | Atom_string v -> v | Atom_float v -> string_of_float v end | Sexp_list list -> let slist = List.map string_of_sexp list in sprintf "[%s]" (String.concat "," slist)
とする。begin .. end は意味的には ( .. ) と同じなのでこっちを使ってもいいが、外見上 begin .. end のほうがわかりやすい。あと、if 式においても
if false then print_endline "Hello "; print_endline "World!"
は C などと同じく
(if false then print_endline "Hello ";) print_endline "World!"
と解釈される。ここでも begin .. end を使う。制御構造とともに使うときには ( .. ) ではなく begin .. end を使うのが良いらしい。
if は特に変わったところはない。OCaml では then 節の値が unit 型の時 else 節は省略できたが、Haskell では省略はできない。SML でもできない。
パターンマッチング。OCaml とそんなに変わらないが、@ を使ったアズパターンに注意。リストの先頭の要素をさらに先頭に加える関数 dupHead は次のようになる。
dupHead lst@(h:_) = h:lst dupHead [] = [] -- 空リストのときは何もしない
OCaml ではこうだ。
let dup_head = function h::_ as lst -> h::lst | [] -> []
Haskell では @ で OCaml では as だが、順番が逆になっている。Haskell では 変数名 @ パターン だが、OCaml では パターン as 変数名 だ。
そしてガード。OCaml では when を使う。Haskell では一つのパターンに対して複数のガードが書ける。OCaml ではガードは一つしか書けない。
パターンマッチングを行うのは match ではなく case だ。SML と同じ。
演算子はその優先順位と結合性を指定できる。SML では演算子を非結合とすることはできなかった気がするが、Haskell ではできる。
let。let は一つの let に対して複数の定義を書ける。SML に近い。where は強いて言えば SML の local に近いか。let と local の違いは、let は式になるのに対して、local は式にはならず宣言になるということだ。Haskell の let は定義の順番によらず、定義内から他の束縛された変数が見える。つまり、Scheme でいうと let や let* でなくいつも letrec を使うようなものだ。OCaml では let rec と and を使う。
7 章終わり。ようやく半分か。