(Redirected from ja/common_error_messages)
このページでは、 OCamlコンパイラが出すエラーや警告メッセージからいくつかについて短く説明していく。 長い説明はたいていチュートリアルの専用のセクションにあるだろう。
オブジェクトの型が使われている文脈で互換性がないときに、 この種のメッセージが頻繁に出てくる。
# 1 + 2.5;; ^^^ This expression has type float but is here used with type int
"This expression has type X but is here used with type Y" (この式は X 型になっているが Y 型であるべきでは?)はこういう意味だ。 式の中身が単独の (2.5)
なのでその型は X (float
) と推論される。 しかし、 文脈つまり (1 + ...)
のような周囲の状況は Y (int
) 型の式を期待するという相違があり、 X と互換性がない。
もっと混乱するのが以下のメッセージだ:
This expression has type my_type but is here used with type my_type
このエラーは普通、トップレベル環境で型定義を幾つかテストするときに起こる。 OCaml では、すでに別の型名になっている名前で型を定義することは完全に合法である。 次のセッションで考えてみよう:
# type my_type = A | B;; type my_type = A | B # let a = A;; val a : my_type = A # type my_type = A | B;; type my_type = A | B # let b = B;; val b : my_type = B # a = b;; This expression has type my_type but is here used with type my_type
コンパイラにとって、2番目の my_type
の定義は最初の定義とは全く独立している。 つまり同じ名前の二つの型を定義したことになる。 "a
" は早々に定義されているので最初の型に属しており、 "b
" は2番目の型に属している。 この例では、 my_type
の最後の定義より後で "a
" を再定義すると問題は解決する。 この種の問題は、 同じモジュール内の同じ型に同じ名前を使うようながっかりなことをしない限り、 実際のプログラムでは起きないだろう。
オプション引数を伴う関数は最低一つのラベル無し引数が必要だ。 たとえはこれは良くない:
# let f ?(x = 0) ~y = print_int (x + y);; Warning: This optional argument cannot be erased val f : ?x:int -> y:int -> unit = <fun>
単にunit型の引数を付け加えれば解決する。こんなふうに:
# let f ?(x = 0) ~y () = print_int (x + y);; val f : ?x:int -> y:int -> unit -> unit = <fun>
ラベルの章で、ラベルつき引数を伴う関数の詳細が分かる。
これは、コンパイル単位(ファイル)の終端に到達したときに、 コンパイラにとってそのオブジェクトの完全な型が分からないが、 何らかの理由で多相型ではいけないような場合に起きる。 例:
let x = ref None
コンパイル中に以下のメッセージが出る:
The type of this expression, '_a option ref, contains type variables that cannot be generalized
解法:例のように型の注釈を付けてコンパイラに教える:
let x : string option ref = ref None
または:
let x = ref (None : string option)
'_a
型のデータは一時的にだけ(たとえばトップレベルセッション)許されている。 これはあたえられたオブジェクトは型が不明だが、 どの型でもなく、多相データでもない。 トップレベル環境では例は以下の結果になる:
# let x = ref None;; val x : '_a option ref = {contents = None}
コンパイラは x
の型がまだ完全には分かっていないことを伝えている。 しかし、あとで x
を使うときにコンパイラは x
の型を推論できる:
# x := Some 0;; - : unit = ()
これで x
は既知の型となった:
# x;; - : int option ref = {contents = Some 0}
OCaml FAQ にもっと詳細がある。
そのようなコードを意図的に残す理由は全くないので、 この警告はエラーとみなすべきだ。 これは以下の状況のように、 何気なく全称パターンを使ったときに起きやすい。
# let test_member x tup = match tup with (y, _) | (_, y) when y = x -> true | _ -> false;; Characters 56-62: Warning: this pattern is unused. (y, _) | (_, y) when y = x -> true ^^^^^^ val test_member : 'a -> 'a * 'a -> bool = <fun>
明らかにこのプログラマは、 OCaml のパターンマッチングのなんたるかについて誤解していた。 以下を覚えておこう:
when
" 節)はパターンの一部ではない。これは高々一度だけ評価される単なる条件であり、次のマッチケースへ飛ぶ最後の手段として使われる。y
" のような束縛) はまさに名前であり、常にマッチする。これで、上の例では最初の組だけがテストされるだけというのは明確だ。 従って以下のような結果になる:
# test_member 1 (1, 0);; - : bool = true # test_member 1 (0, 1);; - : bool = false
OCaml のパターンマッチングは、パターンの組が場合を尽くしているか否かを、 型に基づいてのみチェックできる。 したがって以下の例では、 コンパイラは mod
演算が返すであろう int
の範囲は分からない。
# let is_even x = match x mod 2 with 0 -> true | 1 | -1 -> false;; Characters 18-74: Warning: this pattern-matching is not exhaustive. Here is an example of a value that is not matched: 2 ..match x mod 2 with 0 -> true | 1 | -1 -> false.. val is_even : int -> bool = <fun>
パターンマッチングを使わない解決方法はこの通りだ:
let is_even x = x mod 2 = 0
一般的に、この類の簡単化は不可能であり、 最善解は到達することにない全称ケースを加えることだ:
let is_even x = match x mod 2 with 0 -> true | 1 | -1 -> false | _ -> assert false
古いプログラムを際コンパイルしたり、適切にきれいになってない (訳注: make clean していないような) 外部ソースからプログラムをコンパイルしたりすると、 このようなエラーメッセージを食らうかもしれない。
some_module.cmi is not a compiled interface
これは some_module.cmi
が OCmal コンパイラの現在のバージョンにとっては有効でないという意味だ。 たいてい、古いコンパイル済ファイル (*.cmi
, *.cmo
, *.cmx
, ...) を削除して再コンパイルすれば問題は解決するはずだ。
最近のバージョンの OCaml では、 文字列中の保護されないバックスラッシュ(2つ重ねるべき) を避けるよう警告する。 このようなメッセージは古いプログラムをコンパイルするときにも 出てくることがあるから、 "-w x
"オプションを付けることで表示を消すことが出来る。
Objective Caml version 3.08.2 # "\e\n";; (* bad practice *) ^^ Warning: Illegal backslash escape in string - : string = "\\e\n" # "\\e\n";; (* good practice *) - : string = "\\e\n"