質問
私は実験言語のインタプリタを書いています。言語の主要な構成要素のうちの 3 つは、定義、ステートメント、および式です。定義にはステートメントと式を含めることができ、ステートメントには定義と式を含めることができ、1 種類の式にはステートメントを含めることができます。これらすべてを共用体型を使用して表現しているので、パターン マッチングを簡単に使用できます。理想的には、これらのコードを別のファイルに置きたいのですが、OMake は循環依存関係の問題について不満を抱いています。私の知る限り、モジュール間での循環型定義は許可されていません。
これを解決するために私が知っている唯一の方法は、3 つのタイプすべてを一度に定義することです。
type defn = ...
and stmt = ...
and expr = ...
これには、型のすべてのコードが同じファイル内にある必要があるようです。これを回避する方法はありますか?コード内の循環定義をどのように処理しますか?
解決
再帰的定義は同じファイル内に存在する必要があります。定義、ステートメント、および式を別個のモジュールに分割したい場合は、次を使用して行うことができます。 再帰的モジュール, ただし、同じファイル内に存在する必要があります。ファイル間の依存関係を DAG 化することは、OCaml の問題点の 1 つです。
他のヒント
これは、参照する型をパラメータ化することで簡単に解決できます。
type ('stmt, 'expr) defn = ...
type ('defn, 'expr) stmt = ...
type ('defn, 'stmt) expr = ...
このテクニックは「再帰的な結び目を解く」(ゴーディアンの結び目にちなんで)と呼ばれており、次の文献で説明されています。 OCamlジャーナル 記事。
乾杯、ジョン・ハロップ。
よく使用されるもう 1 つの解決策は、インターフェイス内の型を抽象化することです。インターフェイス内の型は抽象的なため、これらのインターフェイスは再帰的に依存しません。実装では型を指定できますが、実装はインターフェイスのみに依存するため、再帰的でもありません。
唯一の問題は、このソリューションでは、実装の外でこれらの型のパターン マッチングができなくなることです。
個人的には、好みの問題かもしれませんが、プログラムのすべてのタイプを 1 つのモジュールで定義するのが好きです (プログラムの読みやすさに役立つと思います)。したがって、OCaml のこの制限は私にとって実際には問題ではありません。