F#:重载功能

时间:2010-02-14 11:46:18

标签: f#

我的问题与此问题有些相关 - Functions with generic parameter types - 但我无法理解如何做我想做的事。

我想定义一个'后代函数来包含对各种C#类的'Descendants'的调用,如下所示:

让后代名称(xDocument:XDocument)= xDocument.Descendants name

让后代命名(xElement:XElement)= xElement.Descendants name

这种方法不起作用,因为我们有'后代'的重复定义。

我认为可以使用内联函数和静态解析参数来定义以下方法来代替:

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

但是在尝试这样做时我遇到了这个错误:

根据此程序点之前的信息查找不确定类型的对象。在此程序点之前可能需要类型注释来约束对象的类型。这可以允许解析查找。

有没有办法可以写第二个功能来做我想做的事?

2 个答案:

答案 0 :(得分:14)

一般来说,我认为像^x这样的帽子类型可能会被过多使用(至少,从SO的问题数量来判断)。它是一个强大的功能,但它的设计主要是为了解决通用算术问题。我认为他们可以使F#程序不必要地复杂化。

如果您只使用XDocumentXElement,那么答案非常简单,因为您可以使用XContainer这是他们的公共基类并具有{{1方法:

Descendants

如果找不到公共基类,那么你当然可以使用let descendants name (xml:XContainer) = xml.Descendants(name) // Both of these will work fine descendants (XName.Get "foo") xd descendants (XName.Get "foo") xe 类型,但你也可以使用普通的重载,这在F#中是可行的,但只适用于对象类型的成员:

^a

(因为你引用了一个问题,答案已经表明重载与成员合作,这对你来说可能不是什么新鲜事。但是对于将来会发现这个问题的其他人可能会有用。) / p>

答案 1 :(得分:4)

下面的代码编译(并提示调用静态成员约束函数所需的语法)。

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