ocaml中的类型建模

时间:2015-07-06 03:48:27

标签: ocaml algebraic-data-types

我有一组Ocaml类型来表示语法树。有类型的程序,类,方法,表达式等。例如,方法由这样的记录类型表示:

type method = { return:typeid; args:typeid list; body:expr } 

它包括返回类型,每个参数的类型和正文定义。我想键入检查语法树,并生成一种看起来非常类似于旧树的新树,除了每个表达式都有一个与之关联的显式typeid(仅在类型检查后才知道)。

一种选择是声明一组并行类型:

type typed_expr = expr * typeid
type typed_method = { return:typeid; args:typeid list; body:typed_expr }
(* ... there are more types *)

typed_method是必需的,因为typed_expr是一个不同的类型。但我不想为未经检查的AST和已检查的AST维护两组几乎相同的类型。

另一种方法是定义表达式如下:

type expr = {...; typ:typeid option}

这使我能够对检查器的输入和输出使用相同的类型定义。不同之处在于我将大量检查移动到已检查语法树的使用者代码中。这里有一个合同,typ字段在类型检查器输出中永远不会是None,并且在类型检查器输入中始终为None

现在,每次我使用输入树时,访问typ字段内部值的唯一方法是首先检查它是否为None(它不应该是)。由于额外的检查,这使得所有后来的消费者代码都很难看。

这些方法似乎都不令我满意。你会如何模仿这个?

1 个答案:

答案 0 :(得分:4)

第一个比第二个更好:拥有两组看起来相似的数据类型可能很糟糕,但它是安全的:你必须在第二种方法中处理的不变量由类型解决。实际上,OCaml编译器实现采用这种方法:请参阅parsetree.mlitypedtree.mli

在第一个和第二个之间,您可能希望定义typ字段参数化的数据类型:

type 'typ expr = { ...; typ : 'typ }

然后你可以使用unit expr表示无类型AST,typeid expr表示输入AST。

我仍然更喜欢为无类型和类型化设置不同数据类型的第一种方法,因为通常情况下两个世界的AST可能有一些其他差异而不是类型。