tags:

views:

67

answers:

2

I started using FsUnit to test F# code. It makes it possible to express assertion in F# style, for example:

[<Test>]
member this.``Portugal voted for 23 countries in 2001 Eurovision contest``() =
    this.totalVotes 
    |> getYearVotesFromCountry "Portugal" 2001
    |> Seq.length
    |> should equal 23

Note "sould equal 23" that I get from FsUnit. Here's how FsUnit define it:

let equal x = new EqualConstraint(x)

With floating point numbers it's not that simple. I have to use EqualConstraint with Within method. It naturally fits C#:

Assert.That(result).Is.EqualTo(1).Within(0.05);

Of course I'd like to be able to write in F#:

result |> should equal 1 within 0.05

But that does not work. I ended up defining a new function:

let almostEqual x = (new EqualConstraint(x)).Within(0.01)

or if I want to parameterize precision, I can specify it as a second argument:

let equalWithin x y = (new EqualConstraint(x)).Within(y)

But none of them are pretty. I would like to define "within" function in a more natural way for F#, so it can be used together with equal. But F# does not support method overloading, so it looks like I can't define it in such a way so "equal" can be used either alone or together with "within".

Any great ideas?

A: 

Terminology note: F# does support method overloading; it does not support overloading let-bound functions ('free' functions defined in modules).

You could e.g. make it should.equal with a dot, so that equal is a method on the should object, which you could overload. Although that still wouldn't help, since you can't overload curried arguments. Hmmm.

Ok, I don't have much helpful to offer. Personally I don't like these type of syntactic sugars in libraries.

Brian
You're right Brian in terminology. I meant let-bound functions of course.And I enjoy this syntactic sugar. I think it's essential in F#.
Vagif Abilov
+4  A: 

This is an interesting problem! I don't think that you can append within 0.05 to the existing definition of should equal in any way. To do that you would need to add parameter to the should function, but that needs to have a fixed number of parameters in the library.

One way to write this elegantly in F# would is to create custom operator +/-. Note that you still need to use parentheses, but it looks quite neat:

0.9 |> should equal (1.0 +/- 0.5)

The operator simply constructs some value of a special type that needs to be explicitly handled in the equal function. Here is the implementation:

type Range = Within of float * float
let (+/-) (a:float) b = Within(a, b)

let equal x = 
  match box x with 
  | :? Range as r ->
      let (Within(x, within)) = r
      (new EqualConstraint(x)).Within(within)
  | _ ->
    new EqualConstraint(x)
Tomas Petricek
Wow! It is quite need indeed! Thanks for another great suggestion. And this one is also based on custom operators.
Vagif Abilov