Friday, March 11, 2011

Using LINQ to XML from F# (and a bit of duck typing for fun)

So you want to use XML from F#? here are the tips and tricks I discovered today to clear my roadblocks.
Tip 1: Reference the System.XML assembly from FSI so you play with the REPL. To do this I add the #r in block comments at the top of the file  like so:
(* Press Alt-' to send the below to the interpreter.
#r @"C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Xml.Linq.dll"
*)
open System.Xml.Linq
Tip 2: F# doesn’t perform implicit conversions. Lets assume you’re translating the following C# code:
var xelements = XElement.Parse("<myXML/>");
var interestingElements = xelements.Descendants("myXML");
The naive translation below doesn’t work because XElement.Decendants doesn’t take a string, it takes an XName
//FAILS to compile This expression was expected to have type XName but here has type string 
let interestingElements = xelements.Descendants "myXML"
The reason the above code works in C# is because an implicit conversion operator exists and is called. However in F# implicit conversions are not called, and you have to call them yourself, something like the painful to read:
let interestingElements = xelements.Descendants <| XName.op_Implicit "myXML"; 
Now, it turns out we can use duck typing to make an implicit conversion operator (this is mentioned lots of places on the web but I’ll repeat it for succinctness)
// Create an implicit conversion operator, it's inline which means it will work on any types that support the implicit conversion.
// This is duck typing.
let inline convert_implicit(arg : ^source) : ^target = ((^source or ^target) : (static member op_Implicit : ^source -> ^target) (arg)) 
And finally we can write the code I needed:
let interestingElements = xelements.Descendants <|  convert_implicit "myXML"; 

No comments: