模式匹配中的单态类型与默认大小写
Monomorphic type in pattern matching with default case
嗯,其实这不是问题,因为我解决了它,但它太困扰我了:
让我们这样写:
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 File "test.ml", line 6, characters 11-62:
Warning 8: this pattern-matching is not exhaustive. Here is an example
of a value that is not matched: Badd
Compilation finished at Tue Sep 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 File "test.ml", line 13, characters 31-33:
Error: This expression has type char but an expression was expected of
type int
Compilation exited abnormally with code 2 at Tue Sep 13 13:26:48
嗯,什么?我发现 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
Compilation finished at Tue Sep 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)对其进行了测试)。
干得好,您刚刚发现了值限制!
所以,我更愿意以简单的方式回答:
applications are monomorphic !
实际上,更好:
If you're not a function declaration, an identifier or a constant, you can't be polymorphic
但是如果您知道您的类型应该是多态的,那么有一种方法可以通过将其声明为函数来实现。
所以,另一种让它多态的方法是写:
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
和另一个 link 来回答这个问题:http://caml.inria.fr/pub/old_caml_site/FAQ/FAQ_EXPERT-eng.html#polymorphisme
嗯,其实这不是问题,因为我解决了它,但它太困扰我了:
让我们这样写:
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 File "test.ml", line 6, characters 11-62:
Warning 8: this pattern-matching is not exhaustive. Here is an example of a value that is not matched: Badd
Compilation finished at Tue Sep 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 File "test.ml", line 13, characters 31-33:
Error: This expression has type char but an expression was expected of type int
Compilation exited abnormally with code 2 at Tue Sep 13 13:26:48
嗯,什么?我发现 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
Compilation finished at Tue Sep 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)对其进行了测试)。
干得好,您刚刚发现了值限制!
所以,我更愿意以简单的方式回答:
applications are monomorphic !
实际上,更好:
If you're not a function declaration, an identifier or a constant, you can't be polymorphic
但是如果您知道您的类型应该是多态的,那么有一种方法可以通过将其声明为函数来实现。 所以,另一种让它多态的方法是写:
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
和另一个 link 来回答这个问题:http://caml.inria.fr/pub/old_caml_site/FAQ/FAQ_EXPERT-eng.html#polymorphisme