OCaml 編譯器 - 2021 年 10 月

我很樂意發布第四期「OCaml 編譯器開發電子報」。 (這絕非詳盡無遺:許多人最終沒有時間寫東西,這沒關係。)

當然,歡迎隨時評論或提問!

如果您一直在開發 OCaml 編譯器,並且想說些什麼,請隨時在本討論串中發文!如果您希望我下次準備電子報時與您聯繫(未來某個隨機的時間點),請透過電子郵件 (gabriel.scherer at gmail) 告知我。

先前發布的電子報


2021 年 10 月對我們當中的某些人來說是特別的月份,因為這是「序列冰河期 (Sequential Glaciation)」之前的最後一個月 - 在多核 (Multicore) 整合之前,所有與多核無關的功能都會被凍結數個月。

Xavier Leroy (@xavierleroy)

在得知冬天即將到來後,我為了準備 4.14 版本發布而處理了一些未完成的工作,包括更多棄用警告 #10675、正確終止訊號處理 #10726,以及在作業系統允許的情況下增加原生堆疊大小限制 #10736。後者應該可以緩解「堆疊溢位」導致非尾遞迴程式碼在遇到作業系統限制時崩潰的問題。

我也致力於使用更現代的偽隨機數生成 (PRNG) 演算法重新實作 Random 標準函式庫模組。在 RFC#28 中,Gabriel Scherer 建議將標準函式庫 Random 模組的隨機數生成演算法變更為「可分割」的,以便在多核世界中提供更好的行為。(「分割」隨機數生成器狀態會產生兩個獨立的狀態,據說它們會產生獨立的隨機數流;很少有 RNG 演算法支援分割,而且其理論尚未被充分理解。)

我的第一個提案是基於 Xoshiro256++ PRNG,它速度快且統計強度高:#10701。然而,Xoshiro 不支援完全分割,僅支援稱為「跳躍」的有限形式,而討論顯示跳躍是不夠的。然後奇蹟發生了:在完全相同的時間(2021 年 10 月的 OOPSLA 會議),Steele 和 Vigna 提出了 LXM,這是一系列 PRNG,它們具有 Xoshiro 的所有優良特性並支援完全分割。我立即使用 LXM 重新實作了 Random 模組 #10742,我發現結果非常好。我希望這個實作將被選中以取代現有的 Random 模組。

構造函式尾遞迴

Gabriel Scherer (@gasche) 趕在冰河期截止期限前完成了 TMC(構造函式模組尾遞迴)PR (#9760) 的工作,這要歸功於與 Pierre Chambart (@chambart) 的一次安排得當的全天會議,Pierre Chambart 完成了該工作的最後審查。他們設法得到我們都喜歡的東西,並且該功能現在已合併到上游。

請注意,這是 Frédéric Bour (@let-def) 在 2015 年 5 月於 #181 中開始的 TRMC 工作的延續(也是 Basile Clément (@Elarnon) 的主要貢獻);這次合併結束了 OCaml 編譯器最長開啟的開發主題之一。

現在可以這樣寫

let[@tail_mod_cons] rec map f = function
| [] -> []
| x::xs -> f x :: (map[@tailcall]) f xs

並取得有效的 map 尾遞迴定義。

手冊中正在編寫一個章節來描述該功能:#10740

(另一方面,構造函式取消裝箱工作沒有任何進展,必須等到 5.0 版本。)

原生程式碼發射和連結的進展

作為 RFC#15:使用 JIT 的快速原生頂層 的一部分,在原生程式碼發射和連結以及 @NathanRebours 和 David @dra27 提出的原生頂層上進行了一批小變更:#10690、#10714、#10715

用於簡化工具的模組形狀

Ulysse Gérard、Thomas Refis 和 Leo White 在 OCaml 編譯器中提出了一種新的程式分析,旨在幫助外部工具了解實作檔案(OCaml 模組的實作)的結構,特別是實作「定位定義」功能 — 這在存在 includeopen 等的情況下並非易事。

他們分析的結果是「形狀」,它以易於處理且結構豐富的形式描述模組的項目(值、型別等)。

Florian Angeletti (@Octachron) 由於其出色的審查工作,趕在冰河期截止期限前允許合併此 PR。

(PR 的作者最初想為 OCaml 編譯單元新增新種類的編譯成品,以將形狀資訊儲存在 .cms.cmsi 檔案中,而不是過大的 .cmt 檔案中。人們對此感到不滿,因此這部分暫時被排除在外。)

Stdlib 中對 UTF 解碼和驗證的支援

#10710 中,Daniel Bünzli (@dbuenzli) 新增了對 UTF 解碼和驗證的支援,這是標準函式庫中長期以來缺少的功能。API 經過精心設計,可避免分配和例外狀況,同時提供易於使用的解碼介面。

Seq.t 的便捷函式

值隨需 (但不記憶化) 序列的型別 Seq.t 是由 Simon Cruanes (@c-cube) 於 2017 年貢獻的,只有一組最小的函式,此後緩慢增加。在 François Potter (@fpottier) 和 Simon 的努力下,在冰河期之前及時完成了大量 >40 個函式的匯入,這要歸功於 @gasche、@dbuenzli 和其他許多人的審查。這項工作始於 2020 年 2 月,這要歸功於 Yawar Amin 的 #9312 問題。

看這裡

val is_empty : 'a t -> bool
val uncons : 'a t -> ('a * 'a t) option
val length : 'a t -> int
val iter : ('a -> unit) -> 'a t -> unit
val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a
val iteri : (int -> 'a -> unit) -> 'a t -> unit
val fold_lefti : (int -> 'b -> 'a -> 'b) -> 'b -> 'a t -> 'b
val for_all : ('a -> bool) -> 'a t -> bool
val exists : ('a -> bool) -> 'a t -> bool
val find : ('a -> bool) -> 'a t -> 'a option
val find_map : ('a -> 'b option) -> 'a t -> 'b option
val iter2 : ('a -> 'b -> unit) -> 'a t -> 'b t -> unit
val fold_left2 : ('a -> 'b -> 'c -> 'a) -> 'a -> 'b t -> 'c t -> 'a
val for_all2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool
val exists2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool
val equal : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool
val compare : ('a -> 'b -> int) -> 'a t -> 'b t -> int
val init : int -> (int -> 'a) -> 'a t
val unfold : ('b -> ('a * 'b) option) -> 'b -> 'a t
val repeat : 'a -> 'a t
val forever : (unit -> 'a) -> 'a t
val cycle : 'a t -> 'a t
val iterate : ('a -> 'a) -> 'a -> 'a t
val mapi : (int -> 'a -> 'b) -> 'a t -> 'b t
val scan : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b t
val take : int -> 'a t -> 'a t
val drop : int -> 'a t -> 'a t
val take_while : ('a -> bool) -> 'a t -> 'a t
val drop_while : ('a -> bool) -> 'a t -> 'a t
val group : ('a -> 'a -> bool) -> 'a t -> 'a t t
val memoize : 'a t -> 'a t
val once : 'a t -> 'a t
val transpose : 'a t t -> 'a t t
val append : 'a t -> 'a t -> 'a t
val zip : 'a t -> 'b t -> ('a * 'b) t
val map2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t
val interleave : 'a t -> 'a t -> 'a t
val sorted_merge : ('a -> 'a -> int) -> 'a t -> 'a t -> 'a t
val product : 'a t -> 'b t -> ('a * 'b) t
val map_product : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t
val unzip : ('a * 'b) t -> 'a t * 'b t
val split : ('a * 'b) t -> 'a t * 'b t
val partition_map : ('a -> ('b, 'c) Either.t) -> 'a t -> 'b t * 'c t
val partition : ('a -> bool) -> 'a t -> 'a t * 'a t
val of_dispenser : (unit -> 'a option) -> 'a t
val to_dispenser : 'a t -> (unit -> 'a option)
val ints : int -> int t

我們收到的一些新貢獻者的精彩貢獻

Dong An (@kirisky) 完成了 Anukriti Kumar (#9398, #10666) 遺留下來的 PR,以完成 OCAMLRUNPARAM 變數的說明文件。

Dong An 還改進了 README 說明,說明在 MacOS 或 Windows 上應該使用哪個 C 編譯器來建置編譯器程式碼:#10685

感謝 Wiktor Kuchta,ocaml 頂層現在會在啟動時顯示關於 #help 指令以取得說明:#10527。(Wiktor 不再是真正的「新」貢獻者,在過去幾個月中他做出了許多 精彩的貢獻。)

順便一提,@sonologico 在 2020 年 5 月提出的 PR,在幾個月前被合併 (#9621)。它變更了 ocamldebug 除錯器的內部建置系統,以避免在連結使用者定義的列印程式碼時發生模組名稱衝突。大部分延遲來自於維護人員就應該使用哪種十二種名稱衝突避免修復^W 功能而爭論不休。