当一个值包含一个通用值时,为什么OCaml在第一次使用时会修改它的类型?

当一个值包含一个通用值时,为什么OCaml在第一次使用时会修改它的类型?,ocaml,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 =

当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 
#让配对x y z=z x y;;
val对:'a->'b->('a->'b->'c)->'c=
#让第一个p=p(funxy->x);;
val first:(('a->'b->'a)->'c)->'c=
#让第二个p=p(funxy->y);;
第二个值:(('a->'b->'b)->'c)->'c=
#设foo=1.2对“bob”;;
val foo:(浮点->字符串->'\u a)->'\u a=
#第一富;;
-:浮动=1.2
#傅;;
-:(浮动->字符串->浮动)->浮动=
#第二富;;;
错误:此表达式具有类型(float->string->float)->float
但需要类型为的表达式
(浮动->字符串->字符串)->“a”
类型float与类型string不兼容
#设foo=1.2对“bob”;;
val foo:(浮点->字符串->'\u a)->'\u a=
#第二富;;;
-:string=“bob”
#傅;;
-:(浮动->字符串->字符串)->字符串=
#第一富;;
错误:此表达式具有类型(float->string->string)->string
但需要类型为的表达式
(浮动->字符串->浮动)->“a”
类型字符串与类型float不兼容

基本上,foo的类型是
valfoo:(float->string->'\u a)->'\u a=
,但这会改变我们第一次投影第一个或第二个元素的时间。为什么会发生这种情况?

这称为弱多态类型。关于这一点,人们提出并回答了很多问题。请随意使用SO搜索工具或阅读OCaml常见问题解答。但简言之,这是由于值限制,当您有部分应用程序或可变值时,通常会使用值限制。在前一种情况下,您可以使用所谓的eta表达式来增强您的类型(用外行术语来说,就是用普通函数调用替换部分应用程序)。在后一种情况下,无法进行任何操作。

正如@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"
#让配对x y z=z x y;;
val对:'a->'b->('a->'b->'c)->'c=
#让第一个p=p(funxy->x);;
val first:(('a->'b->'a)->'c)->'c=
#让第二个p=p(funxy->y);;
第二个值:(('a->'b->'b)->'c)->'c=
#设foo x=对1.2“bob”x;;
val foo:(浮点->字符串->'a)->'a=
#第一富;;
-:浮动=1.2
#第二富;;;
-:string=“bob”

对于那些感兴趣的人,我在这里找到了相关的FAQ条目: