2013-07-04 17 views
9

mam klasę i rekord zdefiniowany tak:Dlaczego kompilator F # nie działa z tym operatorem?

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 

to zawiedzie skompilować z:

Człon lub obiekt konstruktora 'op_Addition' nie jest publiczna. Dostęp do prywatnych członków można uzyskać tylko z poziomu deklarowanego typu. Dostęp do chronionych członków można uzyskać tylko z typu rozszerzającego i nie można uzyskać do nich dostępu z wewnętrznych wyrażeń lambda.

Oba typy są wewnętrzne. Gdybym jawnie ustawić operatora + celu publicznego, który nie pomaga:

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

Co robi praca jest po prostu rezygnując użycie operatora i za pomocą metody statycznej:

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 

Dlaczego czy kompilator F # ma problemy z używaniem operatora w tym przypadku, gdy używanie nazwanego elementu działa dobrze?

Zmiana obu typów na publiczną zamiast wewnętrzną rozwiązuje również błąd kompilacji.

Używam programu Visual Studio 2012 z kierowaniem F # 3.0 .NET Framework 3.5.

+1

Może to być błąd kompilatora - na pierwszy rzut oka Twój kod wygląda na prawidłowy. Powinieneś wysłać to e-mailem na adres 'fsbugs' w witrynie' microsoft.com', aby zespół F # mógł go przejrzeć. –

+0

To * wygląda * jak błąd dla mnie. Wydaje się, że przy rozwiązywaniu ograniczeń dla 'op_Addition' ograniczenie to' AccessibleFromEverywhere' zamiast 'AccessibleFromSomewhere'. Rzeczywista poprawka wydaje się dość skomplikowana bez wpływu na resztę kompilatora. – vcsjones

Odpowiedz

5

Nie wiem, dlaczego kompilator F # ma ten problem. Jest to prawdopodobnie związane ze sposobem obsługi operatorów w języku F #, a może z obsługą dostępności. Musisz pamiętać, że w tym języku nie wszystko jest takie, jak się wydaje. Niektóre cechy "obiektowe" zostały osiągnięte poprzez pewne poświęcenie. Może to jeden z nich.

Ale. Wiem, jak rozwiązać ten problem :). Nie twórz wewnętrznych typów w pliku implementacji. Zamiast tego użyj podpisów. Definiowanie pliku Foo.fsi tak:

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

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

i Foo.fs takiego:

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 

To sprawia, że ​​kod ważny i MyRecord wewnętrznej.

+0

Użycie pliku sygnatur jest dobrym rozwiązaniem. Pozwala mi zachować składnię, którą lubię. W sugestii JackP w komentarzu podążam w górę, aby sprawdzić, czy zespół F # nie ma o tym myśli. – vcsjones

Powiązane problemy