1

好吧,实际上这不是问题,因为我解决了它,但它太困扰我了:

让我们这样写:

测试.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不是'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

而且它也可以完美编译(但是,eww,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 回答