把函数塞进不该塞的地方
来源: blog.veritates.love — 2026-09-14
概述
作者在写一个编译到 WASM GC 的玩具函数式语言时,遇到一个经典矛盾:他既希望表达式是可以比较、序列化、做属性测试的纯数据,又希望类型能自由选择底层编码,不想维护一张自定义类型注册表、也不想让代码生成器知道各种特化类型。文中先界定「纯数据」的含义:类型需要能合法实现 Show、NFData、Eq、Ord(Read 暂不算),因为函数闭包天生要隐藏数据、无法被归一化,所以函数通常无法嵌入数据。解法是存在类型加去函数化:用 Typeable、NFData、Ord、Show 组成一个约束包,把带类型类字典的语义值包进 ForeignSemantics,再借助全局一致的类型类字典提供函数,最后用 Typeable.cast 配视图模式做模式同义词,让 AST 照常派生 Show/Eq/Ord/NFData 而完全不需要感知里面藏着函数。
核心要点
- 矛盾点在于纯数据必须能合法实现 Show、NFData、Eq、Ord,而函数闭包要隐藏的数据恰恰无法归一化。
- 方案是把函数包进存在类型:用 Typeable 与类型类字典做全局、一致的载体,从而免费获得函数。
- NFData 不会成为障碍,因为全局类型类字典里没有意外的 thunk 或 bottom;Eq 与 Ord 则退化为比较运行期类型反射。
- 最终效果是 AST 照常派生 Generic、Show、Eq、Ord 与 NFData,编译器不必知道里面塞了外部语义。
金句
类型类字典的美妙之处,在于它们提供了全局而一致的字典,以类型为键——因为全局而一致,它们本身不携带数据,你只需要知道它们是什么类型。
👍 0
👎 0
返回 Lobsters 首页