Работа с круговыми зависимостями в OCaml

Я пишу переводчика для экспериментального языка. Три основные конструкции языка - это определения, утверждения и выражения. Определения могут содержать утверждения и выражения, операторы могут содержать определения и выражения, а один вид выражения может содержать утверждения. Я представляю все эти типы соединений, поэтому я могу легко использовать сопоставление шаблонов. В идеале, я хотел бы поместить код для них в разные файлы, но OMake жалуется на проблемы с круговой зависимостью. Насколько я знаю, описания круговых типов в разных модулях не допускаются.

Единственный способ решить эту проблему - определить сразу все три типа:

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

Похоже, для этого требуется, чтобы весь код для типов находился в одном файле. Есть ли способ обойти это? Как вы имеете дело с круговыми определениями в вашем коде?

Ответ 1

Рекурсивные определения должны появляться в одном файле. Если вы хотите разделить определения, выражения и выражения на отдельные модули, вы можете сделать это с помощью рекурсивных модулей, но они все равно должны появиться в тот же файл. DAG-форматирование зависимостей между файлами является одним из неприятностей OCaml.

Ответ 2

Это легко решить путем параметризации ваших типов по типам, к которым они относятся:

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

Этот метод называется "развязывание рекурсивного узла" (в отношении гордиев узла) и описан в статье

Ответ 3

Другое часто используемое решение - это абстрагирование типов в интерфейсах. Поскольку типы являются абстрактными в интерфейсах, эти интерфейсы не зависят от рекурсивно. В реализациях вы можете указать типы, и поскольку реализации зависят только от интерфейсов, они также не являются рекурсивными.

Единственная проблема заключается в том, что с этим решением вы больше не сможете сопоставлять шаблоны с этими типами вне их реализации.

Лично, но это, вероятно, вопрос вкуса, мне нравится иметь все типы моей программы, определенные в одном модуле (я думаю, что это помогает в удобочитаемости программы). Итак, это ограничение OCaml для меня не является проблемой.