2017-01-19 9 views
6

F#の汎用クラスを単一の型パラメータで持ち、ファクトリメソッドを含む静的クラスを作成したいと考えています。私のクラスを書くとき、F#コンパイラは "スコープをエスケープする型変数"に関連するエラーを生成します。私の質問は、エラーがそこにあり、それを修正する理由です。私はタイプFoo<'a>がでファクトリメソッドを呼び出すことができるようにしたいと思いますので、汎用変数と非汎用クラスを結合するときの変数型エスケープスコープ

type Foo<'a>(element : 'a) = 

    member this.Copy() = Bar.Create(element) 

and Bar = 

    static member Create(element : 'a) = new Foo<'a>(element) 

タイプで相互再帰がある:私は問題を実証最小サイズのスニペットを作成しました

静的クラス。上記のスニペットはコンパイルされず、エラーは次のようになります。「型推論によって、型変数aがそのスコープからエスケープされました。明示的な型パラメータ宣言を追加するか、コードをあまり一般的でないように調整することを検討してください。エラーは、BarクラスのCreateメソッドにあるものとして登録されています。残念ながら、私はこの問題を本当に理解していませんし、解決する方法もありません。何か案は?

これ以上のことをご説明します。スニペット

type Foo<'a>(element : 'a) = 

    member this.Element = element 

and Bar = 

    static member Create(element : 'a) = new Foo<'a>(element) 

コンパイルします。したがって、この問題は、Foo<'a>クラスのCopy()メソッドに基づいて行われる型推論に関連するように見えます。また、スニペット

type Foo<'a>(element : 'a) = 

    member this.Copy() = Bar.Create(element) 

and Bar = 

    static member Create<'a>(element) = new Foo<'a>(element) 

は、「このコードは十分に汎用的ではないエラーと、コンパイルされません(静的メソッドを明示的に汎用作られる)コードの複数のC#様バージョンです。型変数 'はスコープをエスケープするため、一般化できませんでした。

答えて

6

再帰メンバの型推論は、しばしば、少なくともいくつかの定義で型名を必要とします。

type Bar = 
    static member Create(element) = Foo(element) 
and Foo<'a>(element:'a) = 
    member this.Copy() = Bar.Create(element) 

(私もBar.Createelementに注釈を削除したことに注意してください)。しかし、時にはあなたは、少なくともあなたの簡素化REPROでできるよう、再発注の定義によってこれを避けることができます。

残念なことに、特定の状況で注釈が必要なのはわかりやすい説明があることはわかりません。

2

私は実際にタイプ変数'aが未解決であることについて、別のエラーを見ている、と私は'aでバーをパラメータ化することによって、それを回避することができます:

type Foo<'a>(element : 'a) = 
    member this.Copy() = Bar.Create(element) 

and Bar<'a> = 
    static member Create(element : 'a) = new Foo<'a>(element) 

私は、私は非常にを持っていない怖いですあなたが相互に再帰的な型を持っているシナリオでこれがなぜ必要なのか、別のBar型を持っているのではないかという良い説明です。

私は相互に再帰的な型を避ける傾向があります。ほとんどの場合、再帰を避けるためにコードを再構成することができます。通常は、必要に応じて読みやすく、リファクタリングしやすいものになります。

+2

相互に再帰的な型を保つことについてのコメントに合意しました。 –

4

これは一般的なBarをせずに動作するようです:

type Foo<'a>(element : 'a) = 
    member this.Copy() = Bar.Create element 
and Bar = 
    static member Create<'a>(element : 'a) : Foo<'a> = Foo(element) 

Online Demo

ちょうど試行錯誤た理由を、全く分かりません。

+1

それは奇妙なものです。おそらく 'Foo'型と' Create'メソッドの型変数の間には、 'Foo <'a>'のように 'Create'の結果がアノテーションなしであると推定されるため、相互作用があります。そんなにうまくいくとは思えません。 – scrwtp

関連する問題