Gleam 語言發布 v1.19.0 版本,其中最重要的變更是由 Giacomo Cavalieri 重寫了 Erlang 程式碼產生器。新產生器不再輸出 Erlang 原始碼,而是直接產生「Erlang 抽象形式」(Erlang abstract forms)。抽象形式是 Erlang 編譯器使用的中間表示法,透過 Erlang 的外部術語格式(External Term Format)進行二進位編碼,使得 Gleam 編譯器可以直接載入生成的程式碼,跳過 Erlang 編譯器的前端處理階段。
此變更帶來多項效益:首先,編譯器效能顯著提升,大幅縮短了執行在 Erlang 上的 Gleam 專案建置時間。其次,執行期可用的位置元數據現在能精確對應到原始的 Gleam 原始碼,而非先前生成的 Erlang 原始碼。這意味著 BEAM 崩潰報告和堆疊追蹤中的行號將完全準確,而先前可能僅指向最近的函數。此外,這也提升了 Gleam 編譯器的程式碼品質,使其符合當前的標準與慣例。
關於為何不直接編譯為 BEAM 位元碼,官方說明 BEAM 位元碼並非固定不變,每個虛擬機版本都可能演進或移除功能,維持同步需要巨大資源。考慮到 Gleam 是依賴贊助的社群專案,資源有限,選擇抽象形式是目前的成本效益最佳點,且與 Elixir 採用的策略一致。
基準測試基於 José Valim 的 langcompilebench 專案,測試編譯 100 個各含 100 個回傳 "hello world" 字串的函數的模組所需時間。比較 v1.17.0 與 v1.19.0 顯示編譯時間顯著減少。擴展測試還將 Gleam 與其他語言比較,結果顯示 Gleam 編譯速度極快,但官方強調這些基準測試是刻意設計的,僅供參考,不能作為對語言特性的絕對結論。
除了 Erlang 後端,v1.19.0 還包含 JavaScript 後端的優化: 1. 決策樹指派優化:John Downey 改進了模式匹配編譯為 JavaScript 的方式,將巢狀 if 語句合併為單一條件,減少中間變數,使生成的程式碼更扁平,有利於 JavaScript 引擎優化。 2. 列表字面值優化:對於短列表,編譯器現在生成更直接的程式碼(使用 prepend 函數),而非先建立 JavaScript 陣列再轉換。這在現代 JavaScript 引擎中帶來效能提升,特別對使用 Lustre 庫等大量短列表的專案有益。長列表仍維持陣列轉換方式。 3. TypeScript API 重載:Giacomo Cavalieri 為生成的 TypeScript 宣告檔案添加了重載,以保留自訂類型的泛型參數,解決了先前類型資訊遺失的問題。
此外,針對其他構建工具的支援也有所改進,包括自動生成 .app 資源檔案、新增 --no-dev 標誌以跳過開發依賴、以及允許將套件資訊輸出到 stdout 等,旨在促進 Gleam 在 Elixir Mix 和 Erlang rebar3 中的整合。語言伺服器也新增了對標籤(labels)的完整支援,包括跳轉定義、尋找參考和重新命名。
事件背景
Gleam 是一種型別安全且可擴展的語言,運行於 Erlang 虛擬機(BEAM)和 JavaScript 執行環境。Erlang 抽象形式是 Erlang 編譯器內部的中間表示法,通常由 Erlang 的分詞器和解析器產生,並使用外部術語格式進行二進位編碼。Elixir 同樣編譯為 Erlang 抽象形式。Gleam 是一個由贊助支持的社群專案,資源相較於企業或學術機構支持的語言較為有限。
社群觀察
社群討論中,用戶 zachrip 讚揚了貢獻者 Giacomo Cavalieri 在 Twitch 直播中的教學貢獻及其友善態度。用戶 0x69420 解釋了 Erlang 抽象形式是 Erlang 編譯器使用的 AST 表示法,並指出 Elixir 也以此為目標。用戶 giancarlostoro 表達了對 Erlang 虛擬機生態系的喜愛,並對 Gleam 的成熟感到高興。用戶 MichaelNolan 讚美 Gleam 語言,並希望未來能編譯為原生目標如 Rust 或 Go。用戶 tiffanyh 指出標題可能具有誤導性,澄清 Gleam 仍然編譯為 Erlang 可用的程式碼,只是格式從原始碼改為抽象形式。



