Using F# to create a Fluent interface

The other day I tried using C# to create a fluent interface around the dotNetRdf library. My aim was to change something like this:


var website = graph.CreateUriNode(UriFactory.Create("https://pollyshaw.wordpress.com"));
var predicate = graph.CreateUriNode("dcterms:author");
var author = graph.CreateLiteralNode("Polly Shaw");
graph.Assert(new[] { new Triple(website, predicate, author) });

which would leave a reader familiar with the domain but perhaps not with the API unsure of what was happening, into something like this:


Graph.AssertTriple(Triple.WithSubject("https://pollyshaw.wordpress.com")
.AndPredicate("dcTerms:author".AsQualifiedName())
.AndObject("Polly Shaw".AsLiteral())

The idea of the fluent interface is that it’s much easier to read and discover how to use than a traditional API containing functions with lots of parameters. Incidentally, I feel that it fixes a problem peculiar to languages which allow parameters to be passed by position rather than name. In Objective-C, which doesn’t encourage this practice, the call might look like this:

[graph assertTripleWithSubject: [Uri uriWithString: @"https://pollyshaw.wordpress.com"]
predicate: [Uri uriWithQName: @"dcTerms:author"]
object: @"Polly Shaw"]

(Please note that the above code is completely made up and not based on any library whatsoever – I’m simply showing what calls could look like in the language.) I am by no means a fan of Objective-C but I do rather like the square-bracket syntax.

Now as I was writing the code I create classes for the return values of the intermediate call. For example Triple.WithSubject(Uri) returned an object that wasn’t exactly a triple, but was a sort of embryonic stage of a triple, which had a subject but needed a predicate and object before it could be viable. (Of course, I could have just returned a proper Triple object and added AndPredicate and AndObject extension methods onto it but I felt that would harm readability and discoverability because it would allow constructs such as Triple.WithSubject(x).AndObject(y).AndPredicate(z), which is surprising to the reader and even Triple.WithSubject(x).AndPredicate(y).AndPredicate(z), whose function is hard to guess.)

These intermediate classes reminded me of something: currying. Currying is the partial evaluation of a function with mulitple parameters to produce another function with fewer parameters. For example suppose we had the function add(x, y) which returned x + y. If our language supported currying, we could create another function addone = add(1) and now addone would be a function taking a single parameter, y, and returning 1 + y. Now the fluent interface reminded me of currying because it felt as though I was doing currying backwards – I was building up towards a function which would create a triple by adding one parameter at a time.

C# does not support currying, although you can use lambdas to create the same outcomes without much more code, e.g. var addone = y => add(1, y). But F# does, and you can write F# libraries that can be called from C#. So I thought I would try writing a fluent interface in F#. To test the concept, I chose to fluentify a function which is much less complicated than the interface to an RDF library: File.Move in System.IO. The definition of this function is:

public static void Move(string fromLocation, string toLocation);

and an example of its use is

File.Move("bad.txt", "worse.txt")

If you don’t know the File class well (and can’t hover over the parameters in your IDE for some reason) you can’t confidently guess by reading the code whether this is moving a file from bad.txt to worse.txt or vice versa. So I think this is a good candidate for fluentification. Something like the following would be much more self explanatory:

Move.From("bad.txt").To("worse.txt");

So I tried to write the above interface in F# using currying. Here is the result:


module Move

// Create a curryable move function based on System.IO.File.Move
let move fromLocation toLocation =
System.IO.File.Move(fromLocation, toLocation)

// Create a type to be returned by the From method taking the partial
// evaluation of move as a constructor parameter
type FromResult(curriedMoveConstructorParam: string -> unit) =
// assign the constructor parameter to a field
    let curriedMove = curriedMoveConstructorParam
// create a method on the class which takes a string parameter
// and completes the evaluation of the constructor parameter
    member this.To(toLocation: string) =
        curriedMove toLocation

// Add a From method to the module which takes a string parameter and
// returns a FromResult formed out of the partial evaluation of move
let From fromLocation =
new FromResult(move fromLocation)

This works, but it isn’t quite what I’d hoped for. It’s disappointing that I’ve created the FromResult type outside the From method so that it’s visible from Intellisense, although I probably could make the constructor internal so that at least no one would be able to create a FromResult object. It would be nicer if I could have returned an anonymous type defined inside the From method. I was also hoping that the code would be much less verbose.

In case it isn’t painfully clear already, I should point out that this is the first F# code I have EVER written outside of a few half-understood and half-completed tutorials. I would definitely welcome suggestions as to how it could be improved.

Advertisements