我正在编写功能样式的编译器。类型检查器目前相当简单:它(大部分)只是从Expr
到Type
的函数。
现在,我想在工作流程中添加一个步骤,以保留后续阶段的类型信息。有很多方法可以做到这一点(符号表等),但一个简单的方法是转换成一个看起来像AST但包含类型信息的IR。例如,如果AST数据类型是:
datatype Expr = Literal of int
| Add of Expr * Expr
| ...
然后输入的IR将是:
type TExpr = Type * TExpr'
datatype TExpr' = TLiteral of int
| TAdd of TExpr * TExpr
| ...
所以我现在的目标是将我的类型检查器转换为类型注释器:函数Expr -> TExpr
而不是Expr -> Type
。这是我的问题:如果不在类型检查器函数中添加一堆样板杂乱,你会怎么做?
天真地,我需要在整个地方添加包装和展开代码,破坏了类型检查器功能的简单易读性。也就是说,类型检查器中的Add
目前的情况如下:
let lhs_t = check lhs in
let rhs_t = check rhs in
case (lhs_t, rhs_t) of
(Int, Int) => Int
| (_, _) => Error
干净整洁!完全符合形式主义的打字判断! ❤️
如果我使用其他翻译逻辑来破坏类型检查程序,它会看起来像这样(现在check
的类型为Expr -> TExpr
):
(* Recursive calls to translate the children. *)
let lhs_typed = check lhs in
let rhs_typed = check rhs in
(* We don't care about the expression for checking, just the resulting
* type. So extract that from each child. *)
let lhs_t, _ = lhs_typed in
let rhs_t, _ = rhs_typed in
case (Int, Int) =>
(* Construct a TExpr with the new type. *)
(Int, TAdd (lhs_typed, rhs_typed))
| (_, _) => Error
令人不快地将有趣的类型检查逻辑与用于破坏和构建TExpr
的无聊样板混合在一起。
有没有办法将这些组件分开?也就是说,类型检查逻辑可以存在于一个递归函数中,而翻译机制可以作为它的外部客户端吗?如果你想要的话,如果仍然很容易运行类型检查器而不用进行翻译,那么奖励积分。
奖金上下文:这是Edward Z. Yang's post on "The AST Typing Problem"的“单独IR”选项。我认为通用编程是la Scrap Your Boilerplate,但不能完全适应这种情况。关于SO的相关但不同的问题: