F#: Passing an argument to a member constraint
I’ve written previously about function overloading in F# and my struggles working out how to do it and last week I came across the concept of inline functions and statically resolved parameters as a potential way to solve that problem.
I came across a problem where I thought I would be able to make use of this while playing around with some code parsing Xml today.
I had a 'descendants' function which I wanted to be applicable against 'XDocument' and 'XElement' so I originally just defined the functions separately forgetting that the compiler wouldn’t allow me to do so as we would have a duplicate definition of the function:
let descendants name (xDocument:XDocument) = xDocument.Descendants name let descendants name (xElement:XElement) = xElement.Descendants name
I wanted to make use of the inline function to define a function which would allow any type which supported the 'Descendants' member:
let inline descendants name (xml:^x) = (^x : (member Descendants : XName -> seq<XElement>) (xml))
I couldn’t work out how I could pass the 'name' input parameter to 'Descendants' so I was getting the following error:
expected 2 expressions, got 1
I posted the problem to StackOverflow and 'Brian' pointed out the syntax that would allow me to do what I wanted:
let inline descendants name (xml:^x) = (^x : (member Descendants : XName -> seq<XElement>) (xml,name))
Tomas Petricek pointed out that in this case we could just write a function which took in 'XContainer' since both the other two types derive from that anyway:
let descendants name (xml:XContainer) = xml.Descendants name
In this situation that certainly makes more sense but it’s good to know how to write the version using member constraints for any future problems I come across.