在OCaml中,这是什么类型的定义:' a。单位 - > '一个

时间:2014-04-27 11:49:18

标签: ocaml

问题

这是我第一次在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假定fint 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 listfoo,所以我做了:

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。

1 个答案:

答案 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.,并且您希望将类型变量的范围限定为单个成员而不是整个对象。