OCaml 4.01.0 変更点
スペルチェック
識別子のミスタイプがあった場合訂正を提案します:
# List.lentgh ;; Characters 0-11: List.lentgh ^^^^^^^^^^^ Error: Unbound value List.lentgh Did you mean length?
個人的には、はあだから?と言った感じかと思っていたのですが、今のところスペルミスを指摘されるとそれはそれでうれしいことが判明しております。
Parser rewriter -ppx
CamlP4 がヘビー過ぎて使えないという虚弱体質な人のために新しい -ppx という物が入りました。はっきり言うと P4 をマスターしている 人には機能が縮小されたものなので嬉しくありません。 まあ使い慣れた Parsetree のレベルでいじれるのが幸いですが…
ocamlc -dsource
コンパイラが受け取ったパースツリーを OCaml の形に出力する機能が付きました。 P4 が組み合わさった複雑なコードがどう展開されているのか確かめるのに役に 立つような気がしますが、ならば P4 を動かしたほうがコメントも残るので 良いのではという気がしますが。(ああ、 -ppx の結果を確認するのに使うつもりなのかな?)
-short-paths というオプションを使うと、データ型に複数の名前がある場合、短いものを表示
これは便利。モジュールやファンクタを沢山使用したコードでは、例えば、:
(* x.ml *) module Very = struct module Long = struct module Module = struct module Name = Hashtbl end end end open Very.Long.Module let tbl = Name.create 107 let () = Name.add tbl 1 2
のようなものを ocamlc -i x.ml でコンパイルすると:
val tbl : (int, int) Very.Long.Module.Name.t
と表示されていましたが、 ocamlc -short-paths -i x.ml とすると
val tbl : (int, int) Hashtbl.t
となります。 -i だけでなく型のプリンタで全て有効。 Core や Batteries を 使っていて標準の型の長い別名があっても短い方に寄せてくれるので型エラーが 読みやすくなります。まあおせっかいに感じることもあるかもしれませんね。
open が既存の名前を覆い隠す時に警告
x が定義済みのところで M.x が存在するモジュールを open M とすると 既存の x の名前が密やかに横取りされるのですが、それに対する警告です:
module M = struct let x = 666 end let x = 42 open M let () = Printf.printf "The answer is %d\n" x
これを ocamlc -w A でコンパイルすると:
Warning 44: this open statement shadows the value identifier x (which is later used)
という警告が出ます。モジュール M の事を知らない人が不用意に open してしまうと x が違う物になってしまうから警告を出すのですね。いや、俺は判ってやってるから文句言わないでくれ、という場合は open M の代わりに open! M と書くと警告がでなくなります。
しかしこれ警告が出たとして直す方法があまりないのですね…コード内の変数の名前を変える、ここでは let x = 42 を let y = 42 にしてその後の x を全部変名する位しか無い。 open M hiding (x) の様な open の全開の挙動を制限する仕組みが無いと警告されても結局無視される恐れがあります。
なお、モジュール名についてはこのチェックが働いていないので中途半端:
module M = struct module List = struct let length = 1 end end open M let x = List.length
List が上書きされるの気持ち悪い人いるはずですね。
アクセント付きアルファベットは識別子名に使えなくなった
OCaml はフランス製なので Latin-1 のアクセント付きアルファベットが 長らく使えたのですが、4.01.0 から deprecated として警告が出ます:
# let caract〓re = 'c';; Characters 4-11: let caract〓re = 'c';; ^^^^^^^ Warning 3: deprecated feature: ISO-Latin1 characters in identifiers Characters 11-12: let caract〓re = 'c';; ^ Error: Illegal character (\168)
[A-Za-z0-9_'] しか識別子に使えません。国際化に背を向ける漢らしい変更ですね!
OCAMLPARAM 環境変数でコンパイラのスイッチのデフォルト変更/オーバーライド可能
オプション -g を付けてデバッグシンボルを付けたい、-annot や -bin-annot を付けて 型情報や定義に飛びたいと思っても第三者のソフトウェアでは Make スクリプト にその指定がない場合、そのスクリプトを一々変更する必要があり大変でした。
OCAMLPARAM 環境変数を使うと一気にコンパイラのスイッチのデフォルトの値や コマンドラインから指定された後、さらにスイッチの値をオーバーライドすることが できるようになりました。便利です:
export OCAMLPARAM=_,g=1,bin-annot=1
とする(bash)と ocamlc を使った場合、 -g -bin-annot が常に付いた 状態になります。 _ の左辺はデフォルト値の変更、右辺はオーバーライドの 変更です:
export OCAMLPARAM="cc=xcc,_,runtime-variant=foo"
だと C コンパイラとしてはデフォルトで xcc を使います。ただし ビルドスクリプト内部で -cc gcc と明示された場合は gcc が使われます。 一方ランタイムは常に foo というものを使うことになります。 これは -runtime-variant bar とスクリプトで指定されていたとしても有効です。
Printexc.get_callstack
コールスタックが欲しい深さで取れるようになりました。
型コンテクストから明らかなコンストラクタとレコードラベルのモジュール名が省略可能
文面から明らかな場合はモジュール名書かなくてよくなりました:
module M = struct type v = Foo | Bar type r = { x : int ; y : int } end let x : M.v = Foo (* M.Foo と書かなくても良い *) let f = function M.Foo -> 1 | Bar -> 2 (* M.Bar と書かなくても良い *) let n = f Bar (* M.Bar と書かなくても良い *) let g r = r.M.x + r.y (* r.M.y と書かなくても良い *)
型が不明の場合はエラーになります。型が明らかな場合でも念のために警告40を 出してきますので使いたい場合は無視対象とすること。
SML の演算子オーバーローディングのコンストラクタやレコードフィールド版かと思いましたが該当部分のコードを見たところコンストラクタの型推論時に型がわかっている場合のみ動くみたいです。つまり後から型コンテキストがわかる場合は救われない。 [M.Foo; Foo] は良いが [Foo; M.Foo] では駄目。不明なコンストラクタやフィールドの推論を delay するのは可能だが面倒なので、まあそんなものかねえ。
caml_modify() と caml_initialize()
PR#6019: more efficient implementation of caml_modify() and caml_initialize(). The new implementations are less lenient than the old ones: now, the destination pointer of caml_modify() must point within the minor or major heaps, and the destination pointer of caml_initialize() must point within the major heap.
ああうう。これは覚えておかねば既存 C コードでクラッシュするかもしれない…