I was reading through Juval Löwy's Programming WCF Services book and wondering if I should do a series of WCF blog posts in F# based on Löwy's book when I ran into a common construct found in C# programs. That construct looks something like the following C# code:
public static void MyMethod(String oldstuff, String newstuff, bool flag) { if (oldstuff == null) throw new Exception("oldstuff is null!"); if (newstuff == null) { DoSomething("Default"); return; } if (flag == false) { DoSomething(oldstuff); return; } DoSomething(newstuff); }
This is a construct that I oftened have used in the past and have never thought about it much. But when you translate the above code directly into F#, it becomes a lot more verbose because F# requires you to implement the then
clause. A direct translation to F# as follows:
let mymethod oldstuff newstuff flag = if oldstuff = null then raise (new Exception("oldstuff is null!")) else if newstuff = null then DoSomething("Default") else if flag = false then DoSomething(oldstuff) else DoSomething(newstuff)
If I had a lot of these if-then-else statements in my C# method, then my F# version would disappear off the screen to the right if I tried to implement it by direct translation. I thought about how I could implement this in F# and came up with this following possibility:
let revised_mymethod oldstuff newstuff flag = let (_,action) = [(oldstuff=null, lazy (raise (new Exception("oldstuff is null!")))); (newstuff=null, lazy (DoSomething("Default"))); (flag=false, lazy (DoSomething(oldstuff))); (flag=true, lazy (DoSomething(newstuff)))] |> List.filter fst |> List.head action.Force()
Rewriting the C# code in this fashion makes me think of rules engines and after refactoring out some common code, I could rewrite the above F# code as follows:
let followrules (xs:(bool*Lazy<unit>) list) = (xs |> List.filter fst |> List.head |> snd).Force() let revised_mymethod2 oldstuff newstuff flag = [(oldstuff=null , lazy (raise (new Exception("oldstuff is null!")))); (newstuff=null, lazy (DoSomething("Default"))); (flag=false, lazy (DoSomething(oldstuff))); (flag=true, lazy (DoSomething(newstuff)))] |> followrules
With this new construct, I can easily re-arrange the order of evaluation, add or remove new conditions. This new construct just seems to have more advantages than the old if-then-else construct in F#.