2013-07-04 3 views
9

私は、クラスなどのように定義されたレコードを持っている:この埋め込み演算子でF#コンパイラが失敗するのはなぜですか?

namespace Foo 
    type internal MyRecord = 
     { 
      aValue1 : int 
      aValue2 : int 
     } 
     static member (+) (left : MyRecord, right : MyRecord) : MyRecord = 
      {aValue1 = left.aValue1 + right.aValue1; aValue2 = left.aValue2 + right.aValue2;} 

    type internal Bar() = 
     member this.Baz() = 
      let myRecord1 = {aValue1 = 2; aValue2 = 3;} 
      let myRecord2 = {aValue1 = 7; aValue2 = 5;} 
      let sum = myRecord1 + myRecord2 //Does not compile 
      0 

これはとコンパイルに失敗します。

メンバーやオブジェクトコンストラクタ」をop_Additionの公開ではありません。プライベートメンバーは宣言型からのみアクセスできます。保護されたメンバは、拡張型からのみアクセスでき、内部のラムダ式からはアクセスできません。

どちらのタイプも内部です。私は明示的に国民に+演算子を設定した場合、それはどちらか助けていません:

namespace Foo 
    type internal MyRecord = 
     { 
      aValue1 : int 
      aValue2 : int 
     } 
     static member Add (left : MyRecord, right : MyRecord) : MyRecord = 
      {aValue1 = left.aValue1 + right.aValue1; aValue2 = left.aValue2 + right.aValue2;} 

    type internal Bar() = 
     member this.Baz() = 
      let myRecord1 = {aValue1 = 2; aValue2 = 3;} 
      let myRecord2 = {aValue1 = 7; aValue2 = 5;} 
      let sum = MyRecord.Add(myRecord1, myRecord2) //Does compile 
      0 

理由:仕事はちょうどオペレータの使用をの前述および静的メソッドを使用している何

static member public (+) (left : MyRecord, right : MyRecord) : MyRecord 

をF#コンパイラは、この場合、名前付きメンバの作業をうまく使えば、演算子を使用するのに苦労していますか?

両方の型を内部ではなくパブリックに変更すると、コンパイルエラーも解決されます。

.NET Framework 3.5をターゲットとするF#3.0でVisual Studio 2012を使用しています。

+1

これはコンパイラのバグです。一見すると、コードは有効であるように見えます。 'microsoft.com 'の' fsbugs'にこれを電子メールで送って、F#チームがそれを調べるようにしてください。 –

+0

これは*私にバグのように見えます。 'op_Addition'の制約を解決するとき、制約は' AccessibleFromSomewhere'ではなく 'AccessibleFromEverywhere'であるようです。実際の修正は、他のコンパイラに影響を与えることなく複雑に見えます。 – vcsjones

答えて

5

なぜF#コンパイラにこの問題があるのか​​わかりません。これはおそらくF#での演算子の扱い方やアクセシビリティの扱い方に関係していると思われます。あなたは、この言葉ではすべてがそうであるとは限りません。いくつかの "オブジェクト指向"の機能は、いくつかの犠牲を払って達成されています。たぶんこれもその一つです。

しかし、私はこれを解決する方法を知っている:)。実装ファイル内で型を内部にしないでください。代わりに署名を使用します。このような

namespace Foo 
    type internal MyRecord = 
     { 
      aValue1 : int 
      aValue2 : int 
     } 

    [<Class>] 
    type Bar = 
     member Baz : unit -> int 

とFoo.fs:

namespace Foo 
    type MyRecord = 
     { 
      aValue1 : int 
      aValue2 : int 
     } 
     static member (+) (left : MyRecord, right : MyRecord) : MyRecord = 
      {aValue1 = left.aValue1 + right.aValue1; aValue2 = left.aValue2 + right.aValue2;} 

    type Bar() = 
     member this.Baz() = 
      let myRecord1 = {aValue1 = 2; aValue2 = 3;} 
      let myRecord2 = {aValue1 = 7; aValue2 = 5;} 
      let sum = myRecord1 + myRecord2 //Compiles 
      0 

これはあなたのコードが有効とMyRecord内部になり、このようにファイルFoo.fsiを定義します。

+0

署名ファイルを使用することは良い解決策です。それは私が好きな構文を維持することができます。コメントの中のJackPの提案では、F#チームがこれについて何か考えているかどうかを確認するためにフォローしています。 – vcsjones

関連する問題