6

参照リンクはOCamlでどのように機能しますか?

例として、3つのモジュールが次のように宣言されていると仮定します。

  • A.ml
  • B.ml
  • C.ml

そのうちの

  • AニーズBC
  • BニーズA

コンパイルはどのように進めればよいですか?

順序はを使用して関連するため、またはとの間の相互参照を修正するにはどうすればよいですocamlcか?ocamloptBA

私は最初にそれらすべてを.cmoでコンパイルしてからすべてocamlc -cをリンクしようとしていますが、引数を交換すると問題がモジュールから別のモジュールに移動するだけなので、成功しません。

具体的なエラーは次のとおりです。

エラー:A.cmoのリンク中にエラーが発生しました:未定義のグローバル`B'への参照

(またはその逆、引数の順序を入れ替えた場合)

これは簡単な質問だと思いますが、解決できません。よろしくお願いします。

4

2 に答える 2

7

モジュールを1つのファイルに結合し、それらを再帰的にする必要があります。2つの別々のファイルのコンパイルプロセスからこれを行う方法はないと思います。

module rec A : 
    sig
        val f : int -> int
        val g : int -> int
    end = 
    struct
        let f x = (B.g x) + 1
        let g x = x + 1
    end
and B :
    sig
        val f : int -> int
        val g : int -> int
    end = 
    struct
        let f x = (A.g x) + 1
        let g x = x + 1
    end

編集:あなたのコメントから、パーサーの型定義と、同じファイル内の型を処理/操作する関数があると思います。私はあなたに同意します、それは理にかなっています。しかし、そのファイルが型を操作するだけでなく、パーサーを呼び出してデータを生成する場合に経験したように、パーサーはどのようにデータを構築しますか?私の解決策は、タイプをそれ自体のモジュールに分離し、操作を実行するモジュールでそのモジュールを開くことでした。

したがって、AAA')に分割します。ここで、はによって生成され、で使用さA'れる型を含みます。あなたの依存関係は、BA

  • AニーズA'B_C
  • BニーズA'

たとえば、作成したアプリケーションを起動するために使用する構成ファイル用のパーサーがあります。

ConfType   --contains the type t  
Conf       --calls parser, and contains helper functions for type ConfType.t  
ConfParser --for ocamlyacc
ConfLexer  --for ocamllex

これに代わる方法は、多形バリアントを使用することです。このようにして、依存関係はアドホックに定義されるため、依存関係を削除します。もちろん、パーサーによって生成されたタイプは、Confのタイプとは異なる可能性があり、コンパイラーはエラーの解決を支援できません。

于 2010-07-01T17:11:27.690 に答える
3

Ocaml言語はモジュール間の再帰をサポートしていますが、コンパイラはコンパイルユニット間の再帰をサポートしていません。だからあなたはA.ml必要B.mlB.ml必要を持つことはできませんA.ml。再帰を削除するためのリファクタリングは、これを簡単に実行できる場合に最適ですが、実行できないと仮定しましょう。

nlucaroniによって説明されているように、1つの解決策は、両方のモジュールを同じファイルに集めて、を使用することmodule recです。別の解決策は、1つのモジュールをファンクターに変換することです。たとえば、の署名を持つ引数をとるAファンクターに変換し、最初にを定義するファイルをコンパイルし、次に、を定義するファイルをコンパイルします。FBFBmodule A = F(B)

Ocamlyaccは物事をより複雑にしますが、あなたはそれをだますことができます!ヘッダーと一致module A = functor (...) -> structするものをフッターに書き込むことができます。ただし、ビルドプロセスの一部として追加するには、生成されたものを書き直す必要があります。(私はあなたが抱えているのと同じ問題を解決するために以前にそれをしたことを知っていますが、どこにいるのか覚えていないので、実際の例をあげることはできません。).mlyend.mlimodule A : functor (...) -> sigend

調査する価値のあるもう1つの可能性は、OcamlyaccからMenhirに切り替えることです。これは、パラメーター化されたパーサーモジュール(つまりファンクター)のサポートなど、役立ついくつかの優れた機能を備えたOcamlyaccの代替品です(構文はほとんどまたはまったく必要ありません)。 。

于 2010-07-08T22:26:40.157 に答える