CHICKEN 6.0.0 将 R7RS 和 Unicode 纳入其核心

Felix Winkelmann 已有 26 年历史的 Scheme 实现获得了现代字符串模型、修订的 C 接口以及可观的迁移成本。

By · Published

Primary source: CHICKEN Scheme

Why it matters

CHICKEN 6 modernizes a 26-year-old compiler without abandoning its compile-to-C design, but its Unicode and R7RS gains require real migration work across existing code and eggs.

Illustration of CHICKEN 6.0.0 core architecture diagram showing integration of R7RS features and a Unicode string model.

CHICKEN 6.0.0 将完整的 R7RS Small 标准和 UTF-8 字符串移入由 Felix L. Winkelmann 在 2000 年开始的 Scheme 实现的核心,同时对足够多的基础 API 进行了更改,因而需要从 CHICKEN 5 进行移植工作。

发行说明并未说明何时发布了最终版本。更稳妥的解读是 6.0.0 是一个公开开发周期的顶点,该周期在本周讨论之前很久就已开始。Peter Bex 在 2024 年 12 月 发布了第一个 6.0.0 预发布版,并请开发者开始测试并移植他们的扩展库,被称为 eggs。

对于 Winkelmann 来说,此次发布延续了他 26 年前做出的一个技术押注:Scheme 可以通过编译为直接的 C 来获得可移植性,而不是将自身绑定到一组狭窄的机器或庞大的运行时。在他 2000 年 7 月 20 日的公告 中,他描述了一个体积小、易于扩展并能生成独立可执行文件的实现。CHICKEN 的 CHICKEN 的当前手册 仍以该模型为中心。其编译器生成可移植的 C,而其解释器支持交互式开发和脚本。

Winkelmann 在 2007 年之前开发 CHICKEN,随后在 2008 年初请社区承担维护责任。他仍然很活跃,CHICKEN 的 CHICKEN 的维护者名录 仍将他标识为作者和核心黑客之一,其他核心成员包括 Peter Bex、Evan Hanson、Kooda 和 megane。其他贡献者负责包管理、测试、文档和基础设施服务,正是这些工作使得一个语言实现即便在原始作者不再独自维护时也能长期可用。

标准进入核心

6.0.0 的决定性变化是将 R7RS Small 指定的每个模块都纳入 CHICKEN 的核心系统。开发者之前依赖外部的 R7RS egg 来获得该层面的标准兼容性。

这种整合影响了熟悉的过程所在的位置。包括 call/ccparameterizeopen-input-stringget-output-string 在内的函数已从 (chicken base) 移动到 (scheme base)case-lambda 现在位于 (scheme case-lambda),而 define-record-type 已移入 (scheme base) 并产生与 R7RS 行为相匹配的生成型记录类型。

CHICKEN 还移除了对若干已被 R7RS 覆盖的旧 SRFI 的模块别名。以前名为 -r5rs-syntax 的编译器和解释器选项现在改为 -r7rs-syntax。旧的 R4RS 和 R5RS 兼容模块已按 (scheme ...) 约定重命名。

这些变化使得符合标准的代码随着时间推移更易于引入 CHICKEN。它们也迫使现有应用停止依赖那些现在属于标准模块的 CHICKEN 特定位置的过程。

UTF-8 改变运行时契约

另一个基础性转变是 CHICKEN 将其内部字符串表示转换为 UTF-8。字符串现在支持 Unicode,文件输入和输出可以指定 UTF-8 或 Latin-1 编码,字符串定位符按代码点而不是字节进行索引。

这项工作影响的不仅是文本显示。CHICKEN 用 (chicken bytevector) 替换了 (chicken blob),提供了与 R7RS 兼容的 bytevector 操作。Bytevector 现在等价于 SRFI-4 的 u8vector 值,旧的 blob 读入语法已被删除,取而代之的是 #u8(...)#u8"..." 形式。

包括 file-readfile-writerandom-bytes 在内的过程现在需要 bytevector 而不再接受字符串。CHICKEN 增加了二进制输入输出端口构造函数以及 bytevector 的读写过程。结果是对编码文本与原始字节之间的更清晰区分,而此前应用可能会模糊这一区别。

这种清晰性带来了迁移成本。将字符串视为字节容器的代码必须更改,而假设一个字节代表一个字符并据此进行索引的代码需要审查。CHICKEN 的 CHICKEN 的迁移指南 将 Unicode、blobs、bytevectors、端口编码、已移动的过程和被移除的 API 列为 CHICKEN 5 用户面临的核心问题。

更广泛的系统更新

版本 6.0.0 还修订了 CHICKEN 的操作系统和 C 接口。诸如 process-forkprocess-runprocess 等进程函数现在返回进程对象而不是单纯的进程标识符。调用方可以通过记录访问器获取状态信息和端口,而等待和发送信号的函数仍然接受对象或 PID。

(chicken file posix) 中的文件锁定现在使用 flock(2),在整个文件上操作,并在发行说明中被描述为线程安全。外部函数接口可以直接传递复数、C 结构体和联合体作为参数和结果。传递给外部代码的字符串和符号不再被复制,这意味着 C 代码所做的变更可从 Scheme 中可见。

构建过程也发生了变化。现在有一个 configure 脚本在 make 之前准备源代码,使 CHICKEN 更接近传统 Unix 的构建惯例。已放弃最小的 Windows 构建,转而采用基于 POSIX shell 的工具链,构建过程可以使用 zig cc 作为替代的 C 编译器和链接器。编译器优化级别现在可以启用闭包重用和共享以减少分配。

Winkelmann 在保持 Scheme 与 C 贴近方面的兴趣在 CHICKEN 6 的工作中得以延续。2024 年,他引入了 CRUNCH,这是一个针对静态类型 R7RS 子集、在 CHICKEN 上运行并输出可移植 C99 的编译器。他将其描述为生成紧凑程序的途径,适用于游戏、虚拟机、嵌入式系统、操作系统组件和对性能敏感的库。

CHICKEN 6 在保留原有架构的同时,为那项工作提供了一个面向标准的基础。该发布并没有用新的运行时或平台目标取代项目的编译为 C 的身份。它更新了有关文本、模块、记录、进程和外部数据的假设,以便相同的架构能够承载针对较新 Scheme 标准编写的代码。

现在的直接工作落在应用和 eggs 的维护者身上。CHICKEN 6 移除了已弃用的过程、重新定位了核心绑定并更改了位于文件处理和外部调用之下的数据表示。好处是便携的 R7RS 代码与 CHICKEN 代码之间的差距变小了。代价是开发者必须将这次大版本迁移当作一次端口工作来对待,而不是一次常规的编译器升级。

Reader comments

Conversation for this story loads after sign-in.