ocaml中的类型建模

ocaml中的类型建模,ocaml,algebraic-data-types,Ocaml,Algebraic Data Types,我有一组Ocaml类型来表示语法树。程序、类、方法、表达式等有多种类型。例如,方法由以下记录类型表示: type method = { return:typeid; args:typeid list; body:expr } 它包括一个返回类型、每个参数的类型和主体定义。我想对语法树进行类型检查,并生成一种新的树,它看起来与旧的树非常相似,只是每个表达式都有一个显式的typeid,只有在与它关联的类型检查之后才知道 一个选项是声明一组并行类型: type typed_expr = expr

我有一组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_方法是必需的,因为typed_expr是另一种类型。但我不想为未检查的AST和已检查的AST维护两组几乎相同的类型

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

type expr = {...; typ:typeid option}
这使我能够对检查器的输入和输出使用相同的类型定义。不同之处在于,我将大量检查移动到检查语法树的使用者代码。这里有一个约定,类型字段永远不会在类型检查器输出中为空,而在类型检查器输入中始终为空

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


这两种方法我都不满意。您将如何对此进行建模?

第一种方法比第二种方法更好:有两组看起来相似的数据类型可能很糟糕,但这是安全的:在第二种方法中,您必须注意的不变量由类型解决。实际上,OCaml编译器实现采用了这种方法:参见parsetree.mli和typedtree.mli

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

type 'typ expr = { ...; typ : 'typ }
然后,可以对非类型化AST使用unit expr,对类型化AST使用typeid expr


我仍然喜欢第一种方法,即对于非类型化和类型化,使用不同的数据类型集,因为这两个世界的AST通常会有一些不同于类型的差异。

为了避免重复,还可以考虑将表达式体排除在类型化AST之外,以便它只携带类型ID。然后,类型化树和非类型化树都需要始终遵循相同的树结构,如果表达式体和id需要在一起,则必须同步迭代这两棵树。-只是个想法,可能是胡说八道