· f

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.

  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket