F#: Overloading functions
My question is somewhat related to this one - Functions with generic parameter types - but I can't quite work out how to do what I want.
I want to define a 'descendants function to wrap the call to 'Descendants' on various C# classes like so:
let descendants name (xDocument:XDocument) = xDocument.Descendants name
let descendants name (xElement:XElement) = xElement.Descendants name
This approach doesn't work because we have a duplicate definition of 'descendants'.
I thought it would be possible to make use of the inline function and statically resolve parameters to define the following method to do this instead:
let inline descendants name (xml : ^x when ^x : (member Descendants : XName -> seq<XElement>)) =
xml.Descendants name
But I'm getting this error when trying to do that:
Lookup on object of indeterminate type based on information prior to this program point. A type annotation may 开发者_JAVA技巧be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
Is there a way that I can write that second function to do what I want?
Generally speaking, I think that hat-types such as ^x
are being maybe used too much (at least, judging by the number of questions about them at SO). It is a powerful feature, but it was really designed mainly to solve problems with generic arithmethic. I think they can make F# programs unnecesarily complicated.
If you're working just with XDocument
and XElement
, then the answer is pretty simple, because you can use XContainer
which is their common base class and has the Descendants
method:
let descendants name (xml:XContainer) = xml.Descendants(name)
// Both of these will work fine
descendants (XName.Get "foo") xd
descendants (XName.Get "foo") xe
If you cannot find a common base class, then you can of course use ^a
type, but you could also use normal overloading, which is possible in F#, but works only for object-type members:
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())
(Since you referenced a question with an answer which already shows that overloading works with members, this probably isn't anything new for you. But it may be useful to others who'll find this question in the future).
Code below compiles (and is suggestive of syntax needed to call static member constraint functions).
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
精彩评论