Phel v0.36.0:將數值塔與一等公變量引入 PHP
Phel 是一種受 Clojure 影響的 Lisp,編譯成 PHP,已發布 0.36.0 版。此更新在語言的精確度與彈性上有重大躍進,加入了強大的數值塔與一等 Var 處理器。對於希望將 Lisp 的表達力與 PHP 生態系的普及度結合的開發者而言,這些變更提供了高精度算術與進階元程式設計的關鍵工具。
數值塔:精確度與任意尺度
在 v0.36.0 中最重要的新增之一是實作了「數值塔」,讓 Phel 能夠處理遠超過標準 PHP 浮點數與整數的精確度。
有理數與大整數
- 精確有理數: Phel 現在支援比例字面值(例如
1/2、-3/4),會直接解析為Rational類型。這消除了分數在浮點除法中固有的四捨五入誤差。 - 大整數支援: 語言現在加入了
BigInteger以支援任意精度的整數。值得注意的是,PHP 整數在算術運算(+、-、*、**)發生溢位時會自動提升為BigInteger,確保計算不會悄悄地環繞或失去精度。 - 大十進位數(BigDecimal): 為了固定精度的十進位算術,現在提供
BigDecimal,使用M後綴字面值(例如1.5M)。
算術行為變更
為了支援此塔,幾個核心行為已經改變。最顯著的是,(/ int int) 若結果不是整數,現在會回傳 Rational,而不是預設為浮點數。需要浮點除法的開發者應明確使用 (double ...),或確保其中一個運算元是浮點數(例如 (/ 1.0 2))。
一等 Var 與動態綁定
0.36.0 版引入了一等 Var 處理器,超越了單純的符號解析,讓開發者能以物件方式操作變數本身。
新的 Var 功能
- Var 處理器: 新的
(var sym)特殊形式與#'sym讀取宏允許建立與操作Var處理器。 - 動態重新綁定: 使用
with-redefs與with-bindings,開發者現在可以從映射重新綁定動態 var,系統會確保即使發生例外,原始值也會被還原。 - 可觀測性:
PhelVarStateRegistry現在支援「監聽」,開發者可使用add-watch與remove-watch在Var透過alter-var-root被變更時觸發動作。
擴充的型別系統與集合
除了數字與 var,Phel 也擴充了原生值型別,以更好地符合現代應用需求:
- UUID: 透過
#uuid "..."、random-uuid與parse-uuid原生支援 UUID。 - 持久佇列(PersistentQueue): 新的
PersistentQueue提供 FIFO 結構,對push、peek、pop操作具備攤銷 O(1) 效能。 - PHP 整合:
PhpClass值型別現在包裝正規化的 PHP 類別/介面全限定名稱(FQN),簡化 Lisp 與 PHP 之間的橋接。 - MapEntry:
MapEntry型別現在在值上等同於 2 元素向量,提升雜湊映射迭代的使用便利性。
效能與工具改進
此版本的效能提升主要聚焦於啟動過程中的開發者體驗(DX):
- 更快的啟動時間: REPL 與測試執行器現在在掃描時會剔除常見的大型目錄,如
vendor/、.git/與node_modules/,且目錄掃描會在每個程序中記憶化。 - 測試最佳化:
phel test指令現在加入了強大的新旗標:--list用於在不執行測試的情況下列出測試,--last-failed用於針對回歸測試迭代,--slowest=N用於找出測試套件中的效能瓶頸。 - 命名空間標準化: 核心函式庫已改為在
(use ...)陳述式中使用點分隔的類別全限定名稱(FQN),提供更一致的語法於整個生態系。
破壞性變更摘要
升級至 v0.36.0 的使用者應留意以下幾項破壞性變更:
- 除法: 當結果不是整數時,
(/ int int)現在回傳Rational而非float。 - UUID:
uuid?現在嚴格只接受Phel\Lang\Uuid物件,而不再接受原始字串。 - 綁定:
binding函式現在對非動態 var 拋出InvalidArgumentException;應改用with-redefs。