簡體   English   中英

在OCaml中,這是什么類型的定義:'a。 單位 - >'a

[英]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 liststring 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM