在OCaml中,这是什么类型定义:';A.单位->';A. 问题

在OCaml中,这是什么类型定义:';A.单位->';A. 问题,ocaml,Ocaml,这是我第一次看到像'a这样的类型定义。单元->“a中 Q1:这是什么'a.(注意点) Q2:这种类型定义的术语是什么 如果我这样做 let f:'a. 'a list -> int = fun l -> List.length l;; 乌托普秀 val f : 'a list -> int = <fun> 但我不能在变体中使用它: type t = Node of ('a. 'a list -> int);; (* this is wrong *) 问

这是我第一次看到像
'a这样的类型定义。单元->“a

Q1:这是什么
'a.
(注意点)

Q2:这种类型定义的术语是什么


如果我这样做

let f:'a. 'a list -> int = fun l -> List.length l;;
乌托普秀

val f : 'a list -> int = <fun>
但我不能在变体中使用它:

type t = Node of ('a. 'a list -> int);; (* this is wrong *)
问题5:为什么


更新/摘要 我对所有类型定义做了一些实验,因为我在OCaml中找不到任何关于这个主题的文章,我想归纳一下背后的原因

我在这里总结了这些实验,希望有人能提供更多的见解


从下面的内容和评论中,我觉得
'a.
是一种对所有事物的
力量

1<代码>'a.
在函数定义中

let f:('a -> int) = fun x -> x + 1 (* correct *) 
因为OCaml可以自由地缩小f参数的类型,并用
int
替换
'a

但是,

let f:'a. ('a -> int) = fun x -> x + 1 (* wrong *)
这不会通过编译器,因为它通过'a强制
f
适用于
所有类型。显然,从定义部分来看,这是不可能的,因为
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
可以在
foo
中处理
int-list
string-list
,所以我做了:

let foo (f:'a. 'a list -> int) = f [1;2;3] + f ["1";"2";"3"];; (* wrong *)
它失败了,OCaml似乎不允许这样做。我想这就是为什么在存在非指示多态性的情况下不能总是进行类型推断,所以OCaml限制了它在记录字段和对象方法时的使用

3<代码>'a.
在记录中

通常我从type参数中获取
'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_记录
,而不再是
'a_记录
。因此,以下操作将失败:

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_记录
本身就是一种具体的记录类型,其
f
可以应用于所有类型的列表。然后我们上面的
foo
将通过OCaml。

'a.
表示“对于所有类型的'a'。OCaml顶级通常不会显示它,这就是为什么它不会出现在输出中。除非在别处显示,否则任何包含类型变量的打印表达式的开头都有一个隐式forall

在定义函数时,在开始时添加该函数以确保类型是多态的可能很有用。e、 g

# let f : ('a -> 'a) = fun x -> x + 1;;
val f : int -> int = <fun>

在定义记录或对象类型时,您需要指定
'a.
,并且您希望将类型变量的作用域设置为单个成员而不是整个对象。

您能回答问题5吗?为什么我不能
type t=Node of('a.'a list->int)?@JacksonTale,这是一个被称为非指示多态性的示例。在存在非指示性多态性的情况下,您不能总是进行类型推断,因此OCaml限制了其用于记录字段和对象方法。在4.00中对类型检查器所做的更改允许GADT,这意味着更广泛地支持非指示性多态性可能不会太难,但还没有人实现它。@LeoWhite so
'a.
强制所有人?这就是为什么
让f:'a。('a->'a)=乐趣x->x+1失败?因为它迫使
f
适用于所有类型,但显然以后它只能应用于
int
?这就是
'a.
的意思吗?@JacksonTale是的,答案就是这么说的
# let f : ('a -> 'a) = fun x -> x + 1;;
val f : int -> int = <fun>
# let f : 'a. ('a -> 'a) = fun x -> x + 1;;
Error: This definition has type int -> int which is less general than
     'a. 'a -> 'a