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))。

一等公民变量与动态绑定

0.36.0 版本引入了一等公民 Var 句柄,超越了简单的符号解析,使开发者能够将变量本身作为对象进行操作。

新的 Var 能力

  • Var 句柄: 新的 (var sym) 特殊形式和 #'sym 读取宏允许创建和操作 Var 句柄。
  • 动态重新绑定: 使用 with-redefswith-bindings,开发者现在可以从映射中重新绑定动态变量,系统会确保即使出现异常也能恢复原始值。
  • 可观察性: PhelVarStateRegistry 现在支持“监视”,开发者可以使用 add-watchremove-watch 在通过 alter-var-root 更改 Var 时触发相应操作。

扩展的类型系统与集合

除了数字和变量,Phel 还扩展了原生值类型集合,以更好地满足现代应用需求:

  • UUID: 通过 #uuid "..."random-uuidparse-uuid 原生支持 UUID。
  • 持久队列: 新的 PersistentQueue 提供 FIFO 结构,对 pushpeekpop 操作具有摊销 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 ...) 语句的类全限定名改为点分隔形式,提供更一致的语法。

破坏性变更概述

升级到 v0.36.0 的用户应注意以下几项破坏性变更:

  1. 除法: 当结果为非整数时,(/ int int) 现在返回 Rational 而非 float
  2. UUID: uuid? 现在严格接受 Phel\Lang\Uuid 对象,而不再接受原始字符串。
  3. 绑定: binding 函数现在对非动态变量抛出 InvalidArgumentException;应改用 with-redefs

Sources