这是我第一次在Explicit polymorphic type in record
中看到类似'a. unit -> 'a
的类型定义
Q1 :这是什么'a.
(注意点)?
Q2 :此类型定义的术语是什么?
如果我这样做
let f:'a. 'a list -> int = fun l -> List.length l;;
utop节目
val f : 'a list -> int = <fun>
Q3 :为什么utop不显示'a. 'a list -> int
类型?
Q4 :我什么时候应该使用这种类型定义?
另外,我可以在记录中使用这种定义:
type t = { f: 'a. 'a list -> int};; (* this is correct *)
但我不能在变体中使用它:
type t = Node of ('a. 'a list -> int);; (* this is wrong *)
Q5 :为什么?
我在这个forall type definition
做了一些实验,因为我在网上找不到关于OCaml中这个主题的任何文章,我想引导找出背后的内容。
我在这里总结了这些实验,并希望有人可以提供更多见解。
从下面的answer及其评论中,我觉得'a.
是一种force forall
的事情。
1。功能定义中的'a.
let f:('a -> int) = fun x -> x + 1 (* correct *)
以上情况很好,因为OCaml可以自由缩小f参数的类型,并将'a
替换为int
。
然而,
let f:'a. ('a -> int) = fun x -> x + 1 (* wrong *)
这不会传递编译器,因为它强制f
通过'a。强加于all types
。显然,定义部分是不可能的,因为x
唯一可能的类型是int
。
这个例子很有意思,因为它显示了OCaml的静态类型推断系统背后的逻辑和魔力。这些类型通常从函数定义中自然地显示出来,即,您更关心函数的作用,而不是首先给出类型。
对我来说,在定义函数时真正使用'a.
是很少见的,就好像函数的定义可以处理所有类型一样,它的类型自然是'a.
;如果函数无论如何都无法处理所有类型,强制所有类型都没有意义。我想这是为什么 OCaml顶层通常不打扰显示它的原因之一
2,'a.
类型推断
let foo f = f [1;2;3] + f [4;5;6] (* correct *)
函数f
将被推断为int list -> int
,因为OCaml首先看到[1;2;3]
并且它是int list
,因此OCaml假定f
将int list
}}。
这也是下面代码失败的原因,因为第二个列表是string list
let foo f = f [1;2;3] + f ["1";"2";"3"] (* wrong*)
即使我知道List.length
会成为f
的合适人选,但由于类型推断系统,OCaml不会允许。
我想如果我强制f为'a.
,那么f
可以处理int list
中的string list
和foo
,所以我做了:
let foo (f:'a. 'a list -> int) = f [1;2;3] + f ["1";"2";"3"];; (* wrong *)
失败了,OCaml似乎不允许它。我猜这就是为什么你不能总是在存在impredicative多态的情况下进行类型推断,因此OCaml限制它用于记录字段和对象方法。
第3。记录中的'a.
通常我从类型参数中取'a
,如下所示:
type 'a a_record = {f: 'a list -> int};; (* correct *)
但是,限制是一旦你申请你得到具体类型:
let foo t = t.f [1;2;3] + t.f [4;5;6];; (* correct *)
OCaml将t
推断为int a_record
,而不是'a a_record
。所以下面会失败:
let foo t = t.f [1;2;3] + t.f ["1";"2";"3"];; (* wrong*)
在这种情况下,我们可以使用'a.
,因为OCaml允许它以记录类型。
type b_record = {f: 'a. 'a list -> int};; (* correct *)
let foo t = t.f [1;2;3] + t.f ["1";"2";"3"];; (* correct *)
b_record
本身就是一个具体的记录类型,它的f
可以应用于所有类型的列表。那么我们上面的foo
将通过OCaml。
答案 0 :(得分:13)
'a.
表示&#34;适用于所有类型&#39; a&#34;。 OCaml顶层通常不会显示它,这就是它不会出现在输出中的原因。打印的任何包含类型变量的表达式在开始时都有一个隐含的forall,除非在别处显示。
定义函数时,在开头添加它可能很有用,以确保类型是多态的。 e.g。
# let f : ('a -> 'a) = fun x -> x + 1;;
val f : int -> int = <fun>
这里,'a -> 'a
只是将函数的输出类型限制为与其输入类型相同,但OCaml可以自由地进一步限制它。使用'a.
,这不会发生:
# let f : 'a. ('a -> 'a) = fun x -> x + 1;;
Error: This definition has type int -> int which is less general than
'a. 'a -> 'a
您需要在定义记录或对象类型时指定'a.
,并且您希望将类型变量的范围限定为单个成员而不是整个对象。