互いに依存し、分離されたファイルで定義されているタイプを定義することは可能ですか?

StackOverflow https://stackoverflow.com/questions/3983509

質問

解析機能を拡張したライブラリを実装しようとしています。私は大学からそれを知っていたので、FSYACCを使用することにしました。残念ながら、私は次の問題に遭遇しました。

私は私の文法の頭のためにクラスを定義しました()そして、その実装を単一のファイルに配置します。次に、パーサーを次のように定義しました。

...
%start head
%type <Head> head
...

FSYACCは浸透モジュールを生成します(パーサー)。成功するには、次の順序でコンパイルする必要があります。 Head.fs Parser.fs

このライブラリを.NETで見つけることができるものと同様にするために、静的を追加したい 解析 方法 . 。残念ながら、私はからの方法を利用する必要があります パーサー モジュール。

私はそのようなことを知っています タイプ依存関係 で解決することができます'オペレーターですが、1つのファイルで定義されたタイプにのみ適用できます。

個別のファイルにある場合でも、互いに依存するタイプを作成する他の方法はありますか? C/C ++のような宣言/実装分離メカニズムを探していましたが、何も見つかりませんでした。

役に立ちましたか?

解決

短い答え:いいえ。 F#2.0の複数のファイルで相互に再帰的なエンティティを行う方法はありません。 (これは、言語の次のバージョンで対処する予定のものです。)

これをさまざまな方法で回避することができます。通常、間接と突然変異のポイントを使用します。たとえば、ヘッドタイプには、関数値を可変グローバル変数に突く静的な「初期ゼパール」メソッドを持つことができ、ヘッドで定義された静的解析方法は、その可変グローバルを介して呼び出すことができ、パーサーが実際に定義された後、 Valueを突くためにInitialIzeParserに電話して電話をかけることができます。

他のヒント

私はそれが可能であることを望んでいました。ブライアンの返事を読んだ後、適切な回避策を探し始めました。ライブラリユーザーに初期化方法を呼び出すことを強制したくありませんでした。したがって、私は何か異なるものを思いつきました。

コンパイラがコンパイル時に依存関係を解決できない場合、実行時に自分でそれを行うことができます。これが私のdepencendciesResolverの定義です

module DependenciesResolver = 
    let GetMethod(_type, _method) =
        lazy (
            let a = System.Reflection.Assembly.GetExecutingAssembly()
            let t = a.GetType(_type)
            t.GetMethod(_method)
            )

分離されたファイルで定義されているクラスの例:

A.fs

namespace MutualRecursion
type A() =
    static member _b = DependenciesResolver.GetMethod("MutualRecursion.B", "b")
    static member b() = A._b.Value.Invoke(null, [||])

b.fs

nameespace MutualRecursion
type B =
    static member b() = 
        printf "Called b()"

編集注文は次のとおりです。A.FSB.FS

これら2つをコンパイルし、新しい方法で頭を拡張する3番目のファイルでこれを回避できませんか?

私は次のようなことをします(ブライアンが提案していたものだと思います)。に注意してください ユーザー トリッキーな初期化を行う必要はありません - タイプ自体は「結び目を結ぶ」方法を知っています。

head.fs

type IParser =
  abstract Parse : string -> int // or whatever
  ...

type Head() =
  static let mutable parser = Unchecked.defaultof<IParser>
  static member internal SetParser p = parser <- p
  member x.DoSomethingCool() =
    let i = parser.Parse("something to parse")
    ...

parser.fs

type Parser private () =
  static do
    Head.SetParser (Parser())
  interface IParser with
    member x.Parse s = 0
    ...
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top