2013-07-04 2 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» конструктор объекта не является общедоступным. Доступ к частным членам возможен только из типа объявления. Защищенные члены могут быть доступны только из расширяемого типа и не могут быть доступны из внутренних лямбда-выражений.

Оба типа являются внутренними. Если я явно задать оператор + для общественности, что не помогает:

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

Что делает работа только отказ от использования оператора и с помощью статического метода:

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 

Почему компилятор F # с использованием оператора в этом случае, когда использование имени члена работает нормально?

Изменение обоих типов, которые будут общедоступными, а не внутренние, также устраняет ошибку компиляции.

Я использую Visual Studio 2012 с таргетингом на F # 3.0 .NET Framework 3.5.

+1

Это может быть ошибка компилятора - с первого взгляда ваш код выглядит так, как будто он должен быть действительным. Вы должны отправить это сообщение в 'fsbugs' на' microsoft.com', чтобы команда F # могла заглянуть в нее. –

+0

Это * выглядит * как ошибка для меня. Похоже, что при разрешении ограничений для 'op_Addition' ограничение является' AccessibleFromEverywhere' вместо 'AccessibleFromSomewhere'. Фактическое исправление выглядит довольно сложно, не влияя на остальную часть компилятора. – vcsjones

ответ

5

Я не знаю, почему компилятор F # имеет эту проблему. Вероятно, это связано с тем, как операторы обрабатываются в F # или, может быть, как обрабатывается доступность. Вы должны помнить, что на этом языке не все так и выглядит. Некоторые «объектно-ориентированные» функции были достигнуты за счет некоторых жертв. Возможно, это один из них.

Но. Я знаю, как это решить :). Не делайте свои типы внутренними в файле реализации. Вместо этого используйте подписи. Определить файл Foo.fsi так:

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 внутренний.

+0

Использование файла подписи является хорошим решением. Это позволяет мне сохранять синтаксис, который мне нравится. По предложению JackP в комментарии я слежу за тем, есть ли у команды F # какие-либо мысли по этому поводу. – vcsjones

Смежные вопросы