まあ、実際にはそれを解決したので問題ではありませんが、あまりにも気になります:
これを書きましょう:
test.ml
type bop = Beq | Bneq | Badd
type value = Vint of int | Vchar of char
let eval bop a b =
let op = match bop with
| Beq -> (=)
| Bneq -> (<>)
in
match a, b with
| Vint i1, Vint i2 -> op i1 i2
| Vchar c1, Vchar c2 -> op c1 c2
| _ -> assert false
コンパイルすると、次のようになります。
ocamlc -o test test.ml ファイル「test.ml」、6 行目、11 ~ 62 文字目:
警告 8: このパターン マッチングは網羅的ではありません。一致しない値の例を次に示します。 Badd
コンパイルは 9 月 13 日火曜日 13:24:50 に終了しました
Badd
これは正常です。ケースを追加するのを忘れていました。
したがって、私は警告が嫌いなので、コードを次のように変更します。
let eval bop a b =
let op = match bop with
| Beq -> (=)
| Bneq -> (<>)
| _ -> assert false (* or exit 1 or raise Exit *)
in
match a, b with
| Vint i1, Vint i2 -> op i1 i2
| Vchar c1, Vchar c2 -> op c1 c2
| _ -> assert false
そして、私はコンパイルします(そして、あなたが理解できるように、ここに不穏な部分があります;-))、私は得ます:
ocamlc -o test test.ml ファイル「test.ml」、13 行目、31 ~ 33 文字目:
エラー: この式は char 型ですが、int 型の式が必要でした
9 月 13 日火曜日 13:26:48 にコード 2 でコンパイルが異常終了しました
さて、何?の型op
が notであること'a -> 'a -> bool
がわかった'_a -> '_a -> bool
ので、コードを変更しました。なぜなら、OCaml では非値の多相型が許可されておらず、部分適用は値ではないことを思い出したからです。となりました:
let eval bop a b =
let op a b = match bop with
| Beq -> a = b
| Bneq -> a <> b
| _ -> assert false
in
match a, b with
| Vint i1, Vint i2 -> op i1 i2
| Vchar c1, Vchar c2 -> op c1 c2
| _ -> assert false
そして私がコンパイルした後:
ocamlc -o テスト test.ml
コンパイルは 9 月 13 日火曜日 13:29:48 に終了しました
私は書くことができた:
let eval bop a b =
let op = match bop with
| Beq -> (=)
| Bneq -> (<>)
| _ -> Obj.magic
in
match a, b with
| Vint i1, Vint i2 -> op i1 i2
| Vchar c1, Vchar c2 -> op c1 c2
| _ -> assert false
そしてそれも完璧にコンパイルされます (しかし、えーと、Obj.magic は低俗な OCaml プログラマーのあだ名にすぎませんよね?)。
それで、ここに私の質問があります。意味的にまったく同じことを書いたときにコンパイラがその動作を変更するのはなぜですか? (OCaml のいくつかのバージョン (3.12.1、4.01.0、4.02.3、4.03.0) でテストしました)。