8.4 よくあるエラー

8.4.1. Cannot find file filename
8.4.2. Corrupted compiled interface filename
8.4.3. This expression has type t1, but is used with type t2
8.4.4. The type of this expression, t, contains type variables that cannot be generalized
8.4.5. Reference to undefined global mod
8.4.6. The external function f is not available

この節ではよく遭遇するエラーメッセージについて説明します。

8.4.1 Cannot find file filename

ファイルをカレントディレクトリまたは探索パス上のディレクトリから見つけることができませんでした。 filename はコンパイル済みインタフェースファイル(.cmi ファイル)ないしはコンパイル済みバイトコードファイル(.cmo ファイル)のいずれかです。 filenamemod.cmi の形式の場合、このエラーは、モジュール mod 中の識別子を参照するファイルをコンパイルしようとしたものの、そのモジュールのインタフェースがまだコンパイルされていなかったことを意味します。 解決策としては、まず、 mod.mli ないしは mod.ml をコンパイルし、コンパイル済みインタフェース mod.cmi を作成してください。

filenamemod.cmo の形式の場合には、存在しないバイトコードオブジェクトをリンクしようとしていることを意味します。 解決策としては、 mod.ml を先にコンパイルしてください。

プログラムを構成するファイルが複数のディレクトリにわたる場合は、ファイルを探索するディレクトリを指定していなかったことによりこのエラーが起こることもあります。 この場合は、コマンドラインに -I オプションを追加してください。

8.4.2 Corrupted compiled interface filename

コンパイラが誤った構造のコンパイル済みインタフェースファイル(.cmi ファイル)を読み込もうとするとこのエラーになります。 これは、この .cmi ファイルを書き込む際に何らかの問題が起こったことを意味します(ディスクが満杯であった、ファイルの作成中にコンパイラが中断された、など)。 .cmi ファイルがコンパイラにより作成されたあとに修正された場合にもこのエラーが起こることがあります。 解決策としては、破損した .cmi ファイルを破棄してビルドしなおしてください。

8.4.3 This expression has type t1, but is used with type t2

これはプログラム中でもっともよく現れる型エラーです。 型 t1 はその式(エラーメッセージに表示されている部分)だけを見て推論された型です。 型 t2 はその式の文脈からその式に期待される型で、この式の値がプログラムの残りの部分でどのように使われるか観察することにより推論されます。 ふたつの型 t1t2 に互換性がない場合、上のエラーが起こります。

ふたつの型 t1t2 に互換性がない理由を理解するのが困難な場合もあります。 例えば、コンパイラが "expression of type foo cannot be used with type foo" と報告し、ふたつの foo 型にはどう見ても互換性があるように見えることがあります。 これは常に正しいとは限りません。 ふたつの型構成子は同一の名前かもしれませんが、実際には別の型を表現しているのです。 これは型構成子が再定義された場合に起こります。 例を示しましょう。

type foo = A | B
let f = function A -> 0 | B -> 1
type foo = C | D
f C

これをコンパイルすると "expression C of type foo cannot be used with type foo" というエラーメッセージを表示します。

8.4.4 The type of this expression, t, contains type variables that cannot be generalized

t 中の型変数 'a, 'b, 'c, ... には一般化された状態と一般化されない状態のふたつの状態があります。 一般化された状態は、型 t が型変数の任意のインスタンスに対して適合する状態を言い、一般化されない状態は、型 t が型変数のただひとつのインスタンスにだけ適合する状態を言います。 let 束縛 let name = expr では、型検査器は通常 expr の型に応じて、型変数を最大限一般化しようとします。 ただし、これを変更可能な多相データ構造と組み合わせると不健全性が発生します(正しく型付けされたプログラムがクラッシュします)。 これを避けるために、 let 束縛での一般化は、束縛式 expr が「構文上の値」のクラスに属している場合にだけ行なわれます。 構文上の値には、定数、識別子、関数、構文上の値のタプルなどが含まれます。 それ以外の場合はすべて(例えば、関数適用の場合)には、変更可能な多相データ構造が作成された可能性があるため、この型の反変または非変部分として現れた型変数をすべて無効にします。 例えば、構文上の値でない式の型が 'a list の場合、この型変数は一般化することができます(list は共変な型構成子です)が、 'a list -> 'a list'a ref は一般化されません(-> の左側は反変で、 ref は非変です)。

一般化されない型変数はそのストラクチャや翻訳単位(.ml ファイルまは対話式セッション)では何の問題もありせんが、シグネチャやコンパイル済みインタフェース(.cmi ファイル)内では使用すると矛盾を起こすことがあるため、使用できません。

そのため、一般化されない型変数を含むような型を持つ値をストラクチャや翻訳単位内で定義するとコンパイラはエラーを報告します。

このエラーを修正する方法はふたつあります。

  • 型制約を追加するか、 .mli ファイルでその名前に型変数のない単相型を指定する。 例えば、

    let sort_int_list = Sort.list (<)
    (* 推論された型 'a list -> 'a list は一般化されない *)

    の代わりに

    let sort_int_list = (Sort.list (<) : int list -> int list);;

    と書きます。

  • 実際に多相型である必要がある場合には、その定義している式に追加の引数を追加して関数にします。 例えば、

    let map_length = List.map Array.length
    (* 推論された型 'a array list -> int list の 'a は一般化されない *)

    の代わりに

    let map_length lv = List.map Array.length lv

    と書きます。

8.4.5 Reference to undefined global mod

このエラーはリンク時に与えたファイルの順序が不完全であったり間違っていた場合に発生します。 また、コマンドラインで mod という翻訳単位の実装(典型的には mod.cmo というファイル、またはそのファイルを格納したライブラリ)を与え忘れた場合にも発生します。 解決策としては、不足していた .ml ファイルや .cmo ファイルをコマンドラインに追加します。 もしくは、モジュール mod の実装は与えていたものの、その順番が後でありすぎた場合には、 mod を参照するすべてのバイトコードよりも前に mod の実装を指定しなければなりません。 この場合の解決策は、コマンドライン中の .ml ファイルと .cmo ファイルの順番を変更することです。

もちろん、モジュールをまたいで相互再帰するような関数があるとこのエラーは常に発生します。 すなわち、関数 Mod1.fMod2.g を呼び出し、 Mod2.gMod1.f を呼び出すような場合です。 この場合、コマンドラインでどのような順番を試しても、リンク時にエラーが発生します。 解決策としては次のようなものがあります。

  • fg を同じモジュールに置く。

  • 片方をもう一方の引数として渡す。すなわち、

    mod1.ml:    let f x = ... Mod2.g ...
    mod2.ml:    let g y = ... Mod1.f ...
    

    とする代わりに、

    mod1.ml:    let f g x = ... g ...
    mod2.ml:    let rec g y = ... Mod1.f g ...
                  

    と定義し、 mod1.cmomod2.cmo より前に指定してリンクします。

  • 次のように、一方を保持するリファレンスを使います。

    mod1.ml:    let forward_g =
                    ref((fun x -> failwith "forward_g") : <type>)
                let f x = ... !forward_g ...
    mod2.ml:    let g y = ... Mod1.f ...
                let _ = Mod1.forward_g := g
                  

8.4.6 The external function f is not available

この関数は C で書かれた外部関数を呼び出すコードをリンクしようとするときに発生します。 18 章「C と Objective Caml のインタフェース で述べるように、そのようなコードは必要な C の関数 f を実装した C ライブラリとリンクしなければなりません。 問題の C ライブラリが共有ライブラリ(DLL)でない場合には、コードはカスタムランタイムモードでリンクしなければなりません。 解決策としては、必要な C ライブラリをコマンドラインに追加し、必要であれば -custom オプションを追加してください。