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


コールスタックが欲しい深さで取れるようになりました。

演算子 |> @@


F# の |> Haskell $ がそれぞれ |> @@ という名前で入りました。めでたい。 私は Haskell $ として & を使い続けますが。

型コンテクストから明らかなコンストラクタとレコードラベルのモジュール名が省略可能


文面から明らかな場合はモジュール名書かなくてよくなりました:

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 コードでクラッシュするかもしれない…