Functional Programming Unit Testing – Using Type Classes Tuesday, January 20, 2009

I wanted to take a brief sidebar from the refactoring conversation that I’ve been having in the past couple of posts, and focus on QuickCheck again. In the next post, I’ll get back to refactoring with HLint. In this post, I want to talk about using type classes to implement operators to use for QuickChecks property-based tests.

Let’s get caught up to where we are today:

Utilizing Type Classes

In the previous post about, “How Would the CLR be Different?”, I stated that I wished the CLR made it easier for higher-kinded polymorpishm to allow for better type classes. But, let’s step back for just a second to talk about how type classes can help us.

Let’s say for example, that we’d like to test for approximate equality for floating-point numbers. Floating point numbers cannot reliably be compared for exact equality. Instead, the algorithm that is used to check for approximate equality is as follows:

abs (x1 - x2) < epsilon

Where we take the absolute value of the difference between the two numbers and compare the result to ensure that it is smaller than epsilon (a rather small number). But, I’d rather have the ability to write the code the way that it makes sense to the reader instead of all the semantics of the approximate equality. Let’s write a test for the way that it should look using an operator as an implementation of approximate equality.

-- Test for property of average

prop_average :: [ Double ] -> Bool

prop_average xs =

(average xs * fromIntegral (length xs)) =~= sum xs



-- Implementation of average

average :: ( Fractional a) => [ a ] -> a

average [] = 0

average xs = sum xs / fromIntegral (length xs)

Our test makes relative sense that the average of a list multiplied by the length should approximately equal the sum of said list. This should always hold true for our tests. But, how do we write that operator? With the beauty of type classes of course. First, let’s look at the implementation of general equality inside Haskell using a type class.

class Eq a where

(==) :: a -> a -> Bool

(/=) :: a -> a –> Bool

This allows us to implement the equality for any given type that we create or use the default implementation given. Let’s take this approach to create an ApproxEq type class so that we can implement it for our comparisons.

class ApproxEq a where

(=~=) :: a -> a -> Bool

(=/~=) :: a -> a –> Bool

We’ve now implement both an approximate equality and approximate inequality function inside our ApproxEq type class. Now to actually use this, we need to create an implementation using double floating-point precision for our average tests. An example might look something like the following:

instance ApproxEq Double where

x =~= x' = abs (x-x') < epsilon

where epsilon = 0.0000001 –- Could be smaller

x =/~= x' = not $ x =~= x')\

Now, when we compile our prop_average, it should now work as expected where I’m checking for approximate equality. We can wire up our property checks in batch form and run as the following:

import Test.QuickCheck

import Test.QuickCheck.Batch



options :: TestOptions

options = TestOptions

{ no_of_tests = 200,

length_of_tests = 1,

debug_tests = False}



main :: IO ()

main = do

runTests "average properties" options

[ run prop_average ]

And when we run through the GHCi console, we get the following results:

ghci> main

average properties : . (200)

We now see that we pass 200 tests, which is something we expected. Moving on over to F#, is this something we can apply? The answer is yes!

Type Classes in F#

I’ve had a lot of thoughts lately around type classes and their importance in the F# language. Unfortunately, there aren’t clean ways to do this. Instead, as Kurt Schelfthout discovered in his post about “A Poor Man’s Type Class”, it can be done, but always the prettiest solution. Let’s go ahead and go for the same ideas as above in the Haskell code in F# and see how it can be accomplished.

The idea, as stated above is to create a test and associated implementation to use an operator to check for approximate equality. Here is how I’d like to write my code:

let prop_average ( xs : float list ) =

( ( List . average xs ) * float ( List . length xs ) ) =~= List . sum xs



[< Fact >]

let test_prop_average ( ) =

check FsCheckExtensions . config prop_average

First, let’s define the interface much as we did above for our type class above to check for both approximate equality and inequality:

type IApproxEq<'a> =

abstract member approxequal : 'a -> 'a -> bool

abstract member approxinequal : 'a -> 'a – > bool

Now, we need the ability to store the associations of the type instances of our given interface. This allows us to query a table to see whether one has been implemented or not.

[< AbstractClass >]

[< Sealed >]

type ApproxEqAssociations private ( ) =

static let associations = new System.Collections.Hashtable ( )

static member Add<'a> ( approxEqual : IApproxEq<'a> ) =

associations . Add ( typeof<'a>, approxEqual )

static member Get<'a> ( ) =

let a = associations . [ typeof<'a >]

match a with

| null ->

failwithf "Type %s does not have an implementation of IApproxEq"

( string ( typeof<'a> ) )

| : ? IApproxEq<'a> -> a : ?> IApproxEq<'a>

| _ ->

failwithf "Type %s has an incorrect implementation of IApproxEq"

( string ( typeof<'a> ) )

What we’ve implemented here is a static class that will let us both add and get instances of our IApproxEq type instances based upon a given incoming type. This gives us the capability now of creating instances of our ApproxEq class and and adding it to the associations table such as this:

// Provide instances of the type class, and register these

type DoubleApproxEqual ( ) =

let epsilon = 0 .000001

let approxEq x x' = abs ( x - x' ) < epsilon



interface IApproxEq< float > with

member this . approxequal x x' = approxEq x x'

member this . approxinequal x x' = not ( approxEq x x' )



ApproxEqAssociations . Add ( new DoubleApproxEqual ( ) )

Once the class has been created and then added to the association table, we can then retrieve it any time we need through the use of our ApproxEqAssociations.Get method. Let’s not stop there, because now I want to create some operators that will then act upon this association to allow us to check for approximate equality. Those are defined below:

// Define an operator which references the associations table

let ( =~= ) x x' = ApproxEqAssociations . Get ( ) . approxequal x x'

let ( =/~= ) x x' = ApproxEqAssociations . Get ( ) . approxinequal x x'

Now that everything is defined, it should just work through our handy FSI command prompt such as the following:

> quickCheck prop_average;;

-Ok, passed 100 tests .

And there you have it, we have type classes that can help improve the design of our code. Is it checked at compile time whether we have an instance or not? The answer, is unfortunately, no. That’s why our tests are of greater importance to verify the behavior of these type classes.

Conclusion

As you can see, we have the ability to define type classes in such a way as to abstract such things as checking for approximate equality. This allows us to write the code the way it should be, instead of worrying about underlying complexity that is checking for such a thing as approximate equality. Using techniques such as this also allows us to generalize our functions in such a way that we get maximum reuse.

Next time, we’ll move back to our refactoring topics and cover refactoring and cleaning our code using HLint.