filename
t1
, but is used with type t2
t
, contains type variables that cannot be generalizedmod
f
is not availableこの節ではよく遭遇するエラーメッセージについて説明します。
ファイルをカレントディレクトリまたは探索パス上のディレクトリから見つけることができませんでした。
filename
はコンパイル済みインタフェースファイル(.cmi
ファイル)ないしはコンパイル済みバイトコードファイル(.cmo
ファイル)のいずれかです。
filename
が
の形式の場合、このエラーは、モジュール mod
.cmimod
中の識別子を参照するファイルをコンパイルしようとしたものの、そのモジュールのインタフェースがまだコンパイルされていなかったことを意味します。
解決策としては、まず、
ないしは mod
.mli
をコンパイルし、コンパイル済みインタフェース mod
.ml
を作成してください。
mod
.cmi
filename
が
の形式の場合には、存在しないバイトコードオブジェクトをリンクしようとしていることを意味します。
解決策としては、 mod
.cmo
を先にコンパイルしてください。
mod
.ml
プログラムを構成するファイルが複数のディレクトリにわたる場合は、ファイルを探索するディレクトリを指定していなかったことによりこのエラーが起こることもあります。
この場合は、コマンドラインに -I
オプションを追加してください。
コンパイラが誤った構造のコンパイル済みインタフェースファイル(.cmi
ファイル)を読み込もうとするとこのエラーになります。
これは、この .cmi
ファイルを書き込む際に何らかの問題が起こったことを意味します(ディスクが満杯であった、ファイルの作成中にコンパイラが中断された、など)。 .cmi
ファイルがコンパイラにより作成されたあとに修正された場合にもこのエラーが起こることがあります。
解決策としては、破損した .cmi
ファイルを破棄してビルドしなおしてください。
これはプログラム中でもっともよく現れる型エラーです。
型 t1
はその式(エラーメッセージに表示されている部分)だけを見て推論された型です。
型 t2
はその式の文脈からその式に期待される型で、この式の値がプログラムの残りの部分でどのように使われるか観察することにより推論されます。
ふたつの型 t1
と t2
に互換性がない場合、上のエラーが起こります。
ふたつの型 t1
と t2
に互換性がない理由を理解するのが困難な場合もあります。
例えば、コンパイラが "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"
というエラーメッセージを表示します。
型 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
と書きます。
このエラーはリンク時に与えたファイルの順序が不完全であったり間違っていた場合に発生します。
また、コマンドラインで mod
という翻訳単位の実装(典型的には
というファイル、またはそのファイルを格納したライブラリ)を与え忘れた場合にも発生します。
解決策としては、不足していた mod
.cmo.ml
ファイルや .cmo
ファイルをコマンドラインに追加します。
もしくは、モジュール mod
の実装は与えていたものの、その順番が後でありすぎた場合には、 mod
を参照するすべてのバイトコードよりも前に mod
の実装を指定しなければなりません。
この場合の解決策は、コマンドライン中の .ml
ファイルと .cmo
ファイルの順番を変更することです。
もちろん、モジュールをまたいで相互再帰するような関数があるとこのエラーは常に発生します。
すなわち、関数 Mod1.f
が Mod2.g
を呼び出し、
Mod2.g
が Mod1.f
を呼び出すような場合です。
この場合、コマンドラインでどのような順番を試しても、リンク時にエラーが発生します。
解決策としては次のようなものがあります。
f
と g
を同じモジュールに置く。
片方をもう一方の引数として渡す。すなわち、
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.cmo
を mod2.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
この関数は C で書かれた外部関数を呼び出すコードをリンクしようとするときに発生します。
18 章「C と Objective Caml のインタフェース」 で述べるように、そのようなコードは必要な C の関数 f
を実装した C ライブラリとリンクしなければなりません。
問題の C ライブラリが共有ライブラリ(DLL)でない場合には、コードはカスタムランタイムモードでリンクしなければなりません。
解決策としては、必要な C ライブラリをコマンドラインに追加し、必要であれば -custom
オプションを追加してください。