在 OCaml 中处理循环依赖

发布于 2024-07-04 18:13:04 字数 359 浏览 6 评论 0 原文

我正在为一种实验语言编写一个解释器。 该语言的三个主要结构是定义、语句和表达式。 定义可以包含语句和表达式,语句可以包含定义和表达式,一种表达式可以包含语句。 我使用联合类型表示所有这些,因此我可以轻松地对它们使用模式匹配。 理想情况下,我想将这些代码放在不同的文件中,但 OMake 抱怨循环依赖问题。 据我所知,跨模块的循环类型定义是不允许的。

我知道解决这个问题的唯一方法是同时定义所有三种类型:

type defn = ...
and stmt = ...
and expr = ...

似乎这需要类型的所有代码都位于同一个文件中。 有没有办法解决? 您如何处理代码中的循环定义?

I'm writing an interpreter for an experimental language. Three of the main constructs of the language are definitions, statements, and expressions. Definitions can contain statements and expressions, statements can contain definitions and expressions, and one kind of expression can contain statements. I represent all of these using union types so I can easily use pattern matching on them. Ideally, I would like to put the code for these in different files, but OMake complains about circular dependency issues. As far as I know, circular type definitions across modules are not allowed.

The only way I know of to solve this is to define all three types at once:

type defn = ...
and stmt = ...
and expr = ...

It seems like this requires all the code for types to be in the same file. Is there any way around this? How do you deal with circular definitions in your code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

笑,眼淚并存 2024-07-11 18:13:04

递归定义需要出现在同一文件中。 如果要将定义、语句和表达式分离到单独的模块中,可以使用 递归模块,但它们仍然需要出现在同一个文件中。 DAG 化文件间依赖关系是 OCaml 的烦恼之一。

Recursive definitions need to appear in the same file. If you want to separate definitions, statements, and expressions into separate modules, you can do so using recursive modules, but they will still need to appear in the same file. DAG-ifying inter-file dependencies is one of the annoyances of OCaml.

遗忘曾经 2024-07-11 18:13:04

另一个经常使用的解决方案是抽象接口中的类型。 由于接口中的类型是抽象的,因此这些接口不是递归依赖的。 在实现中,您可以指定类型,并且由于实现仅依赖于接口,因此它们也不是递归的。

唯一的问题是,使用此解决方案,您无法再在其实现之外对这些类型进行模式匹配。

就我个人而言,但这可能是一个品味问题,我喜欢将程序的所有类型定义在一个模块中(我认为这有助于提高程序的可读性)。 所以,OCaml 的这个限制对我来说并不是真正的问题。

Another solution often used is to abstract the types in the interfaces. Since the types are abstract in the interfaces, these interfaces are not recursively dependent. In the implementations, you can specify the types, and since the implementations depend only on the interfaces, they are not recursive either.

The only problem is that, with this solution, you cannot anymore pattern-matching on these types outside of their implementation.

Personally, but it is probably a matter of taste, I like to have all the types of my program defined in one module (I think it helps in the readability of the program). So, this restriction of OCaml is not really a problem for me.

孤寂小茶 2024-07-11 18:13:04

通过将类型参数化为它们所引用的类型,可以轻松解决此问题:

type ('stmt, 'expr) defn = ...
type ('defn, 'expr) stmt = ...
type ('defn, 'stmt) expr = ...

这种技术称为“解开递归结”(参考 Gordian 结),并在 OCaml Journal 文章。

干杯,
乔恩·哈罗普。

This is easily solved by parameterizing your types over the types they refer to:

type ('stmt, 'expr) defn = ...
type ('defn, 'expr) stmt = ...
type ('defn, 'stmt) expr = ...

This technique is called "untying the recursive knot" (in reference to Gordian's knot) and was described in an OCaml Journal article.

Cheers,
Jon Harrop.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文