1

まあ、実際にはそれを解決したので問題ではありませんが、あまりにも気になります:

これを書きましょう:

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) でテストしました)。

4

2 に答える 2

2

よくできました。値の制限を発見しました!

ここで教育的な説明。技術的な詳細はこちら.

于 2016-09-13T12:03:20.233 に答える
1

だから、私は簡単な方法で答えるのが好きです:

アプリケーションは単形性です!

実際には、さらに良い:

関数宣言、識別子、または定数でない場合、多態的であることはできません

しかし、型がポリモーフィックであるべきだとわかっている場合は、それを関数として宣言する方法があります。したがって、ポリモーフィックにする別の方法は、次のように書くことです。

let eval bop a b = 
  let op = match bop with
    | Beq -> (=) 
    | Bneq -> (<>) 
    | _ -> fun _ -> assert false
  in
  match a, b with
    | Vint i1, Vint i2 -> op i1 i2
    | Vchar c1, Vchar c2 -> op c1 c2
    | _ -> assert false

これに答える別のリンク: http://caml.inria.fr/pub/old_caml_site/FAQ/FAQ_EXPERT-eng.html#polymorphisme

于 2016-09-13T12:17:17.793 に答える