![](/img/trans.png)
[英]In OCaml, what is the difference between `'a.` and `type a.` and when to use each?
[英]In OCaml, what type definition is this: 'a. unit -> 'a
這是我第一次看到類似'a. unit -> 'a
類型定義'a. unit -> 'a
'a. unit -> 'a
in in Explicit polymorphic in record
Q1 :這是什么'a.
(注意點)?
Q2 :這種類型定義的術語是什么?
如果我做
let f:'a. 'a list -> int = fun l -> List.length l;;
utop顯示
val f : 'a list -> int = <fun>
問題3 :為什么utop不顯示類型'a. 'a list -> int
'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中這個主題的任何文章,我想引導找出背后的內容。
我在這里總結了這些實驗,並希望有人可以提供更多見解。
從下面的答案和它的評論,我覺得'a.
是一種force forall
東西。
'a.
在函數定義中
let f:('a -> int) = fun x -> x + 1 (* correct *)
上面是好的,因為OCaml可以自由地縮小f參數的類型並將'a
替換'a
int
。
然而,
let f:'a. ('a -> int) = fun x -> x + 1 (* wrong *)
這不會傳遞編譯器,因為它強制f
通過'a適用於all types
。 。 顯然,從定義部分開始是不可能的,因為x
的唯一可能類型是int
。
這個例子很有意思,因為它顯示了OCaml的靜態類型推斷系統背后的邏輯和魔力。 這些類型通常從函數定義中自然地顯示出來,即,您更關心函數的作用,而不是首先給出類型。
對我而言,真正使用'a.
很少見'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似乎不允許它。 我猜這就是為什么你不能總是在存在impredicative多態的情況下進行類型推斷,因此OCaml限制它用於記錄字段和對象方法。
'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。
'a.
意思是“適用於所有類型”。 OCaml頂級通常不會顯示它,這就是為什么它沒有出現在輸出中。 除非在別處顯示,否則打印的任何包含類型變量的表達式在開始時都具有隱式forall。
定義函數時,在開始時添加它可能很有用,以確保類型是多態的。 例如
# 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.
定義記錄或對象類型時,您希望將類型變量的范圍限定為單個成員而不是整個對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.