在玩具函数式语言的解释器中,我有一个expr
类型,每个算术运算符和布尔运算符都有一个构造函数。我想将这种类型分解为:
type expr =
| Int of int
| BinaryArith of (int -> int -> int) * expr * expr
| Comparison of ('a -> 'a -> bool) * expr * expr
但是,这不会键入,因为未定义'a
类型参数。我可以完全参数化为'a expr
,但是expr
的单个实例将不再提供多态行为。
最终,我的愿望是将内置的比较运算符(<>
、>=
等)传递给构造函数,所以我想在这里保留完整的多态性。
如果构造函数可以被视为函数,那么不可能实现的一个简单原因是 Hindley-Milner 类型系统仅支持"prenex"多态性。
我在这里做错了什么吗?有没有实现这种多态性的适当方法?
编辑:虽然接受者的答案解决了这个问题,但在其他答案和评论中提出了更好的设计。请务必阅读它们!
它并没有完全回答您的问题,但您可能希望让您的 AST 更具象征意义。例如:
type comparison_op = Eq | Ne | Lt | Gt | Le | Ge
type expr = ... | Comparison of comparison_op * expr * expr
然后,当您计算表达式时,您可以调用(=)
或(<=)
等。
我不能排除这是 XY 问题的一个实例,但如果你真的需要它,从 OCaml 4.03 开始有可能有内联记录,即将记录类型(可以具有完全多态字段)直接声明为类型构造函数的参数,如下所示:
type expr =
| Int of int
| BinaryArith of (int -> int -> int)
| Comparison of { compare: 'a. 'a -> 'a -> bool }
let e = Comparison { compare = Pervasives.(=) }