在玩具功能语言的翻译中,我有一个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”多态性。
我在这里做错了吗?有没有一种实现这种多态性的正确方法?
编辑:虽然接受者答案解决了这个问题,但在其他答案和评论中提出了更好的设计。一定要阅读它们!
答案 0 :(得分:5)
它并没有完全回答你的问题,但你可能想让你的AST更具象征意义。例如:
type comparison_op = Eq | Ne | Lt | Gt | Le | Ge
type expr = ... | Comparison of comparison_op * expr * expr
然后,当您评估表达式时,可以拨打(=)
或(<=)
等。
答案 1 :(得分:3)
我不能排除这是XY problem的一个实例,但是如果你真的需要它,那么从OCaml 4.03开始就有可能inline records,即声明记录type(可以具有完全多态字段)直接作为类型构造函数的参数,如:
type expr =
| Int of int
| BinaryArith of (int -> int -> int)
| Comparison of { compare: 'a. 'a -> 'a -> bool }
let e = Comparison { compare = Pervasives.(=) }