模式匹配中的单态类型与默认情况

时间:2016-09-13 11:37:40

标签: polymorphism ocaml monomorphism

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

让我们写下这个:

  

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的类型不是'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 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)测试了它。)

2 个答案:

答案 0 :(得分:2)

干得好,你刚刚发现了价值限制!

教学解释here。技术细节here

答案 1 :(得分: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