2013-08-06 79 views
7

Vấn đề của tôi, trong Tóm lại, là thế này:F # so vs C# IComparable

Tôi có thể làm gì về việc lưu trữ một tuple (hoặc bất kỳ loại với một hạn chế của 'so') trong một # chứa C đòi hỏi phải có một IComparable?

này hoạt động:

> let x (y : 'a when 'a : comparison) = y ;; 
val x : y:'a -> 'a when 'a : comparison 

> x (1,2) ;; 
val it : int * int = (1, 2) 

Tôi đã có thể nghĩ điều này sẽ làm việc:

> let x (y : IComparable<int>) = y ;; 

val x : y:IComparable<int> -> IComparable<int> 

> x (1,2) ;; 

    x (1,2) ;; 
    ---^^^ 

stdin(28,4): error FS0001: The type ''a * 'b' is not compatible with the type 'IComparable<int>' 

Và đây cũng như:

> let x (y : IComparable) = y ;; 

val x : y:IComparable -> IComparable 

> x (1,2) ;; 

    x (1,2) ;; 
    ---^^^ 

stdin(30,4): error FS0001: The type ''a * 'b' is not compatible with the type 'IComparable' 

EDIT

Tôi thực hiện theo các đối số rằng F # không thực hiện upcasting ngầm. Tuy nhiên, ngay cả một cách rõ ràng:

> (1, 2) :> IComparable ;; 

    (1, 2) :> IComparable ;; 
    ^^^^^^^^^^^^^^^^^^^^^ 

stdin(43,1): error FS0193: Type constraint mismatch. The type 
    int * int  
is not compatible with type 
    IComparable  
The type 'int * int' is not compatible with the type 'IComparable' 

Tôi cho rằng điều này làm cho cảm giác như là so sánh của một F # tuple được suy ra cấu trúc bên trong F # hệ thống loại, và có lẽ là thông tin thêm là không có sẵn cho .NET.

Có vẻ như một cách giải quyết mỗi một bình luận dưới đây là cách gọi

Tuple<_,_> (1,2) ;; 

Hoặc thậm chí

box (1, 2) :?> IComparable ;; 
+0

Nó có vẻ kỳ lạ, 'int * int' cụ,' IComparable' (bạn có thể kiểm tra điều này với '(1,2) .GetType() GetInterfaces() '), nhưng trình biên dịch sẽ không cho phép bạn bỏ chạy. Điều này có thể là một số loại hạn chế F # lạ. Tôi tưởng tượng rằng bạn có thể viết một phương thức C# để thực hiện kiểu truyền. –

+0

Tôi đã cập nhật phản hồi của mình để chính xác hơn. Xin lỗi vì những lỗi lầm. –

Trả lời

1

Chắc chắn một số điều kỳ lạ đang diễn ra. FWIW, nó hoạt động nếu bạn xây dựng một System.Tuple<_, _> một cách rõ ràng, do đó có thể là một cách giải quyết:

let x (y : IComparable) = y 
let t = (2, 3) 

x (Tuple<_,_> t) 
7

F # không làm upcasting ngầm như C# làm. Nếu bạn yêu cầu một IComparable, sau đó bạn đang yêu cầu một IComparablekhôngmột cái gì đó mà có thể bị ném lên trời để IComparable

gì bạn thực sự muốn, đang yêu cầu một loại, điều đó xảy ra để thực hiện IComparable, nhưng bạn vẫn đang làm việc với loại cụ thể.

Đó là lý do let x (y : 'a when 'a : comparison), thấy rằng y là loại 'a, trong khi 'a có thể tĩnh bị ném lên trời để comparison (nếu bạn muốn truy cập vào một thành viên của comparison, bạn sẽ phải upCast để comparison sử dụng :> đầu tiên)

Mặt khác, let x (y : IComparable<int>) = y yêu cầu rất rõ ràng là IComparable<int>. Nhưng bạn đang vượt qua (1,2), một giá trị, có thể là upcast đến IComparable. Vì vậy, nếu bạn vượt qua (1,2) :> IComparable<int> hoặc thậm chí (1,2) :> _, trình biên dịch sẽ có thể chuyển giá trị . Bạn có thể kết hợp số so sánh, nhưngbạn mất thông tin loại, giá trị trả lại sẽ là IComparable và không còn là int*int.

let wrapComparable value = 
    { 
     new IComparable with 
      member this.CompareTo other = 
       match other with 
       | :? 'a as other -> compare value other 
       | _ -> raise <| InvalidOperationException() 
    } 

Ngoài ra, ở đây bạn cần phải xem xét, rằng IComparable được dựa trên obj, do đó bạn có thể cần phải xem xét các trường hợp, nơi other của bạn là của một loại khác nhau.

Trong trường hợp, bạn chỉ cần IComparable<'a> mã trở nên đơn giản hơn:

let wrapComparable value = 
    { 
     new IComparable<_> with 
      member this.CompareTo other = compare value other 
    } 

Như vậy, như một quy luật của, bạn thường muốn thực hiện một generic chức năng với các ràng buộc loại, thay vì yêu cầu một giao diện, như bạn sẽ làm trong C#. Điều này là do thực tế, rằng F # không tự động upcasting.

Giải thích rất chi tiết về bình đẳng và so sánh có thể được tìm thấy trong http://lorgonblog.wordpress.com/2009/11/08/motivating-f-equality-and-comparison-constraints/http://blogs.msdn.com/b/dsyme/archive/2009/11/08/equality-and-comparison-constraints-in-f-1-9-7.aspx. Ngoài ra các trạng thái MSDN, rằng

Nếu bạn chỉ sử dụng bộ dữ liệu từ F # và không hiển thị chúng sang ngôn ngữ khác và nếu bạn không nhắm mục tiêu phiên bản .NET Framework trước phiên bản 4, bạn có thể bỏ qua phần.

Các bộ dữ liệu được biên dịch thành các đối tượng thuộc một trong một số loại chung chung, tất cả Tuple có tên, bị quá tải trên số nguyên hoặc số tham số kiểu. Các loại tuple xuất hiện trong biểu mẫu này khi bạn xem chúng từ một ngôn ngữ khác, chẳng hạn như C# hoặc Visual Basic hoặc khi bạn đang sử dụng công cụ không nhận thức được cấu trúc F #. Các kiểu Tuple đã được giới thiệu trong .NET Framework 4. Nếu bạn đang nhắm mục tiêu phiên bản .NET Framework trước đó, trình biên dịch sử dụng các phiên bản của System.Tuple từ phiên bản 2.0 của Thư viện lõi F #. Các loại trong thư viện này chỉ được sử dụng cho các ứng dụng nhắm mục tiêu phiên bản 2.0, 3.0 và 3.5 của .NET Framework. Kiểu chuyển tiếp được sử dụng để đảm bảo khả năng tương thích nhị phân giữa các thành phần .NET Framework 2.0 và .NET Framework 4 F #.

Vì vậy, có vẻ như, rằng thực tế, rằng Tuples, xảy ra được System.Tuple là thực sự chỉ là một chi tiết thực hiện tại thời điểm đó, việc thiếu IComparison làm cho hơi có ý nghĩa.

+0

Cảm ơn bạn đã tham khảo tuyệt vời. Tôi đoán câu hỏi của tôi không rõ ràng 100%. Tôi quan tâm đặc biệt đến interop giữa F # và C#, nơi API C# của tôi yêu cầu một IComparable và tôi không thể chuyển các bộ dữ liệu thô, có cấu trúc so sánh vào API đó. Điều đó có vẻ giống như một thiếu sót thực hiện? –

+0

Vâng, câu hỏi của bạn hơi khó trả lời mà không nhìn thấy chữ ký C#. Nhưng nếu nó là một bộ sưu tập, ngay cả trong C# tôi sẽ sử dụng một chung chung bị ràng buộc, bởi vì một trở về một giao diện mất một số thông tin kiểu. Chữ ký của mã bạn đang sử dụng là gì? –