2013-07-04 38 views
9

Tôi có một lớp và một kỷ lục được xác định như sau:Tại sao trình biên dịch F # thất bại với toán tử infix này?

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 

này thất bại trong việc biên dịch với:

Các thành viên hoặc 'op_Addition' đối tượng constructor không được công khai. Các thành viên cá nhân chỉ có thể được truy cập từ bên trong loại khai báo. Các thành viên được bảo vệ chỉ có thể được truy cập từ một loại mở rộng và không thể truy cập được từ các biểu thức lambda bên trong.

Cả hai loại đều là nội bộ. Nếu tôi dứt khoát thiết lập các nhà điều hành + cho công chúng, điều đó không giúp được gì:

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

không công việc chỉ được ít ưu điểm sử dụng của một nhà điều hành và sử dụng một phương pháp tĩnh:

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 

Tại sao hiện F # trình biên dịch đấu tranh với việc sử dụng một nhà điều hành trong trường hợp này khi sử dụng một thành viên được đặt tên làm việc tốt?

Thay đổi cả hai loại thành công khai thay vì nội bộ cũng giải quyết được lỗi biên dịch.

Tôi đang sử dụng Visual Studio 2012 với nhắm mục tiêu F # 3.0 .NET Framework 3.5.

+1

Đây có thể là lỗi trình biên dịch - trong nháy mắt, mã của bạn có vẻ như nó phải hợp lệ. Bạn nên gửi email này đến 'fsbugs' tại' microsoft.com' để nhóm F # có thể xem xét nó. –

+0

Điều này * trông * giống như một lỗi đối với tôi. Có vẻ như khi giải quyết các ràng buộc cho 'op_Addition', ràng buộc là' AccessibleFromEverywhere' thay vì 'AccessibleFromSomewhere'. Các sửa chữa thực tế xuất hiện khá phức tạp mà không ảnh hưởng đến phần còn lại của trình biên dịch. – vcsjones

Trả lời

5

Tôi không biết tại sao trình biên dịch F # có vấn đề này. Điều này có thể được kết nối với cách các toán tử được xử lý trong F # hoặc có thể cách xử lý truy cập. Bạn phải nhớ rằng trong ngôn ngữ này không phải tất cả mọi thứ là những gì nó có vẻ. Một số tính năng "hướng đối tượng" đã đạt được bằng cách thực hiện một số hy sinh. Có lẽ đây là một trong số họ.

Nhưng. Tôi biết cách giải quyết vấn đề này :). Không làm cho các loại nội bộ của bạn trong tệp triển khai. Thay vào đó hãy sử dụng Chữ ký. Xác định tập tin Foo.fsi như thế này:

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

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

và Foo.fs như thế này:

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 

Điều này làm cho mã của bạn hợp lệ và MyRecord nội bộ.

+0

Sử dụng một tập tin chữ ký là một giải pháp tốt. Nó cho phép tôi giữ cú pháp tôi thích. Theo gợi ý của JackP trong bình luận tôi đang theo dõi để xem liệu đội F # có bất kỳ suy nghĩ nào về điều này không. – vcsjones

Các vấn đề liên quan