一个叫 Goeteia 的开源项目把 Scheme 编译器整个搬进了浏览器。开发者 guenchi 在个人站点演示了一个用 Scheme 编写的编译器,能在浏览器里把 Scheme 代码编译成 WebAssembly,全程不依赖服务器。这个编译器本身也是用 Scheme 子集写的,实现了自举(bootstrap)——用自己的代码编译自己,输出字节完全一致,CI 每次变更都会校验这个不动点。
技术细节上,这个编译器压缩后约 70KB,首次加载后缓存在本地,每次编译约 15 毫秒。Scheme 的 Fixnum 用 i31ref 非装箱存储,对象和记录用 GC 结构体,eq? 直接对应一个引用比较。语法系统同时支持 syntax-rules 和带 fender 的 procedural syntax-case,卫生宏通过重命名在编译时解释器里实现。函数调用做了优化:每个闭包有按参数数量的专用入口和通用入口两种路径,variadic 过程和 apply 调用成本很低,所有尾调用都编译成 Wasm 的 return_call,100M 次循环在约 150 毫秒内跑完,常量栈空间。逃逸续体(escape continuation)借助 Wasm exception-handling 提案实现,捕获是 O(1),普通路径只有一个 try 块,winder 从内向外展开。
标准库方面,项目提供了一系列 web 模块:(web sx) 是细粒度响应式信号驱动的模板系统,(web html) 渲染 DOM,(web js) 做 FFI 直达宿主 JS 环境——演示页面本身就是用它搭的。(web three) 用类似 sx 的方式构建响应式 Three.js 场景,(web gl) 通过命令缓冲区驱动原生 WebGL,每帧一次桥接调用,GLSL 着色器直接写 s-expression。后端如果也用 Scheme(Igropyr),请求响应都是 s-expression 格式,RPC 调用如 (rpc "/rpc" '(add 1 2 1/2)) 返回 (ok 7/2),精确保留分数。(web fetch) 通过 Wasm JSPI 做直接风格网络请求,(web ws) 和 (web sse) 推送数据流,(web json) 处理其他格式。库系统采用 R6RS 风格,支持 (library ...) 和 (import (math utils)) 这样的依赖解析,未使用代码会在构建时被剪裁。
已编译的模块可以在任何支持 Wasm GC 和尾调用的引擎上运行:Node 22+、当前版本的 Chrome / Firefox / Safari,以及 wasmtime。从源码自举需要 Chez Scheme,但项目中已包含可直接使用的编译器 WASM 文件,不需要 Scheme 运行时。
编注:材料为开发者个人站点介绍帖,含技术原理与演示说明;未涉及社区反馈或后续版本计划。