2010-02-14 35 views
6

Câu hỏi của tôi có liên quan đến vấn đề này - Functions with generic parameter types - nhưng tôi hoàn toàn không thể biết cách làm những gì tôi muốn.F #: Chức năng quá tải

Tôi muốn xác định một 'hậu duệ chức năng để quấn cuộc gọi đến 'hậu duệ' trên C# lớp học khác nhau như vậy:

để con cháu tên (XDocument: XDocument) = xDocument.Descendants tên

để con cháu name (xElement: XElement) = xElement.Descendants name

Cách tiếp cận này không hiệu quả vì chúng tôi có định nghĩa trùng lặp về 'hậu duệ'.

Tôi nghĩ rằng nó sẽ có thể tận dụng các chức năng nội tuyến và tĩnh giải quyết các thông số để xác định các phương pháp sau đây để làm điều này thay vì:

let inline descendants name (xml : ^x when ^x : (member Descendants : XName -> seq<XElement>)) = 
    xml.Descendants name 

Nhưng tôi nhận được lỗi này khi cố gắng để làm điều đó :

Tra cứu đối tượng không xác định loại dựa trên thông tin trước điểm chương trình này. Một chú thích kiểu có thể cần thiết trước điểm chương trình này để hạn chế loại đối tượng. Điều này có thể cho phép tra cứu được giải quyết.

Có cách nào để tôi có thể viết hàm thứ hai đó để làm những gì tôi muốn không?

Trả lời

4

Mã bên dưới biên dịch (và gợi ý cú pháp cần thiết để gọi các hàm ràng buộc thành viên tĩnh).

open System.Xml.Linq 

let descendants1 name (xDocument:XDocument) = xDocument.Descendants name 

let descendants2 name (xElement:XElement) = xElement.Descendants name 

let inline descendants name (xml : ^x when ^x : (member Descendants : XName -> seq<XElement>)) = 
    (^x : (member Descendants : XName -> seq<XElement>) (xml,name)) 

let xd = XDocument.Load("http://www.somexml.com") 
let ds = descendants (XName.op_Implicit "foo") xd 
let xe = XElement.Load("http://www.somexml.com") 
let eds = descendants (XName.op_Implicit "foo") xe 
14

Nói chung, tôi nghĩ rằng hat-loại như ^x đang được có thể sử dụng quá nhiều (ít nhất, căn cứ vào số câu hỏi về họ tại SO). Nó là một tính năng mạnh mẽ, nhưng nó thực sự được thiết kế chủ yếu để giải quyết các vấn đề chung với số học. Tôi nghĩ rằng họ có thể làm cho các chương trình F # trở nên phức tạp một cách không cần thiết.

Nếu bạn đang làm việc chỉ với XDocumentXElement, thì câu trả lời là khá đơn giản, bởi vì bạn có thể sử dụng XContainer đó là lớp cơ sở chung của họ và có Descendants phương pháp:

let descendants name (xml:XContainer) = xml.Descendants(name) 

// Both of these will work fine 
descendants (XName.Get "foo") xd 
descendants (XName.Get "foo") xe 

Nếu bạn không thể tìm thấy một lớp cơ sở chung, sau đó bạn có thể sử dụng tất nhiên ^a loại, nhưng bạn cũng có thể sử dụng quá tải bình thường, mà có thể trong F #, nhưng chỉ hoạt động cho các thành viên đối tượng loại:

type Xml = 
    static member Descendants(name, x:XDocument) = x.Descendants(name) 
    static member Descendants(name, x:SomeOtherClass) = x.SomeOtherDescendants(name) 

// The usage looks like this: 
Xml.Descendants(XName.Get "foo", xd) 
Xml.Descendants(XName.Get "foo", new SomeOtherClass()) 

(Vì bạn đã tham chiếu một câu hỏi với câu trả lời đã cho thấy quá tải hoạt động với các thành viên, điều này có lẽ không phải là điều mới mẻ đối với bạn. Nhưng nó có thể hữu ích cho những người khác sẽ tìm thấy câu hỏi này trong tương lai).

+0

Ah Tôi đã không nhận ra rằng quá tải chỉ làm việc cho các thành viên thực sự, rõ ràng là không đọc bài đăng khác đủ chặt chẽ! Cũng không nhận được rằng cả hai đều thừa hưởng từ XContainer vì vậy cảm ơn, đó là một giải pháp tốt hơn nhiều –

+0

Tôi đã thử quá tải bình thường thực sự và trình biên dịch nói rằng có 2 thành viên được gọi là 'Hậu duệ' với cùng số đối số –

+0

Trong một số trước đó phiên bản, F # compiler yêu cầu '[]' được sử dụng khi quá tải, nhưng tôi không chắc chắn trong phiên bản này đã được gỡ bỏ mặc dù ... Tôi chỉ cần thử ví dụ đơn giản trong F # RC (hai phương pháp , cả hai với hai đối số) và nó hoạt động tốt (không có 'OverloadID'). –

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