6 f#
我的问题与这个问题有些相关 - 具有通用参数类型的函数 - 但我无法弄清楚如何做我想要的事情.
我想定义一个'后代函数来包含对各种C#类的'Descendants'的调用,如下所示:
让后代名称(xDocument:XDocument)= xDocument.Descendants名称
让后代命名(xElement:XElement)= xElement.Descendants name
这种方法不起作用,因为我们有'后代'的重复定义.
我认为可以使用内联函数和静态解析参数来定义以下方法来代替:
let inline descendants name (xml : ^x when ^x : (member Descendants : XName -> seq<XElement>)) =
xml.Descendants name
Run Code Online (Sandbox Code Playgroud)
但是在尝试这样做时我遇到了这个错误:
根据此程序点之前的信息查找不确定类型的对象.在此程序点之前可能需要类型注释来约束对象的类型.这可以允许解析查找.
有没有办法可以写第二个功能来做我想做的事情?
Tom*_*cek 14
一般来说,我认为帽子类型^x
可能会被过多使用(至少,从SO的问题数量来判断).它是一个强大的功能,但它的设计主要是为了解决通用算术问题.我认为他们可以使F#程序不必要地复杂化.
如果您正在使用XDocument
和XElement
,那么答案很简单,因为您可以使用XContainer
哪个是它们的公共基类并具有以下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
Run Code Online (Sandbox Code Playgroud)
如果你找不到一个公共基类,那么你当然可以使用^a
类型,但你也可以使用普通的重载,这在F#中是可能的,但只适用于对象类型的成员:
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())
Run Code Online (Sandbox Code Playgroud)
(因为你引用了一个问题,答案已经表明重载与成员一起工作,这对你来说可能不是什么新鲜事.但是对于将来会发现这个问题的其他人可能会有用).
下面的代码可编译(并暗示调用静态成员约束函数所需的语法)。
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
Run Code Online (Sandbox Code Playgroud)