为什么OCaml在包含通用时首次使用时会修改值的类型?

时间:2015-03-17 00:36:30

标签: ocaml

为什么OCaml在包含通用时会更改首次使用的值的类型?例如,如果我们为元组定义一个Church编码,我们有:

# let pair x y z = z x y;;
val pair : 'a -> 'b -> ('a -> 'b -> 'c) -> 'c = <fun>
# let first p = p (fun x y-> x);;
val first : (('a -> 'b -> 'a) -> 'c) -> 'c = <fun>
# let second p = p (fun x y -> y);;
val second : (('a -> 'b -> 'b) -> 'c) -> 'c = <fun>
# let foo = pair 1.2 "bob";;
val foo : (float -> string -> '_a) -> '_a = <fun>
# first foo;;
- : float = 1.2
# foo;;
- : (float -> string -> float) -> float = <fun>
# second foo;;
Error: This expression has type (float -> string -> float) -> float
       but an expression was expected of type
         (float -> string -> string) -> 'a
       Type float is not compatible with type string 
# let foo = pair 1.2 "bob";;
val foo : (float -> string -> '_a) -> '_a = <fun>
# second foo;;
- : string = "bob"
# foo;;
- : (float -> string -> string) -> string = <fun>
# first foo;;
Error: This expression has type (float -> string -> string) -> string
       but an expression was expected of type
         (float -> string -> float) -> 'a
       Type string is not compatible with type float 

基本上,foo的类型为val foo : (float -> string -> '_a) -> '_a = <fun>,但这会在我们第一次投出第一个或第二个元素时发生变化。为什么会这样?

2 个答案:

答案 0 :(得分:2)

这称为弱多态类型。有很多问题被问到并回答了这个问题。随意使用SO搜索工具或阅读OCaml常见问题解答。但简而言之,这是由于价值限制,当您有部分应用或可变值时,通常会发挥作用。在前一种情况下,你可以使用所谓的eta-expression来增强你的类型(用外行术语来表示,用普通函数调用替换部分应用程序)。在后一种情况下,不能做任何事情。

答案 1 :(得分:1)

正如@ivg所说,这是价值限制。以下是使用eta扩展时的工作原理:

# let pair x y z = z x y;;
val pair : 'a -> 'b -> ('a -> 'b -> 'c) -> 'c = <fun>
# let first p = p (fun x y -> x);;
val first : (('a -> 'b -> 'a) -> 'c) -> 'c = <fun>
# let second p = p (fun x y -> y);;
val second : (('a -> 'b -> 'b) -> 'c) -> 'c = <fun>
# let foo x = pair 1.2 "bob" x;;
val foo : (float -> string -> 'a) -> 'a = <fun>
# first foo;;
- : float = 1.2
# second foo;;
- : string = "bob"