[Haskell-cafe] Testing Implementation vs Model - Records or Type Classes?

Heinrich Apfelmus apfelmus at quantentunnel.de
Fri Apr 8 11:54:51 CEST 2011


Hello,

I'm writing a small Haskell library for functional reactive programming. 
The core of the library consists of two data types and several 
primitives. However, I have programmed this core *twice*: once as a 
*model* that displays the intended semantics, and once as the actual 
*implementation* to be used in production code.

Of course, I would like to use QuickCheck to test that the 
implementation gives the same results as the model. My problem is: how 
to organize this with the minimum amount of boilerplate?

It appears that I can use *multiparameter type classes* to solve this, 
but I'm not sure I'm happy with this, in particular because it makes the 
generated Haddock less readable (see 3) below). On the other hand, I 
could also use *record wildcards* to conveniently reify a module into a 
record data structure. But that will give me problems with combinators 
that are derived from the core combinators (see 2) below).

Haskell Café, what are your suggestions and ideas?


In particular, I wish to:

1) Write examples to be QuickChecked only once.
I imagine that my main function for testing looks like this

     test_equal example =
       forAll $ \input -> example model input
                       == example implementation input

where  example  an expression involving the combinators from my library. 
The point is that I don't want to write  example  twice, once for each 
version.

2) Use derived combinators.
For reference, here the full signature of the core combinators:

    data Event a
    data Behavior a

    instance Functor Behavior
    instance Applicative Behavior
    instance Functor Event
    instance Monoid  (Event a)

    filter :: (a -> Bool) -> Event a -> Event a
    apply  :: Behavior (a -> b) -> Event a -> Event b
    accumB :: a -> Event (a -> a) -> Behavior a

When writing tests, I also want to use common derived combinators, like, say

    filterJust :: Event (Maybe a) -> Event a
    filterJust = fmap fromJust . filter isJust

without implementing them twice.

3) Obtain readable Haddock.
I like the simplicity and readability of an ordinary module signature. 
In contrast, libraries with many type class scare me. Or is there a way 
to make this less scary?

I'm not sure about the last one:
4) Make both model and implementation available to the user,
so that he can QuickCheck his own programs as well. Since the 
implementation makes heavy use of IO, it is a bit harder to test 
automatically, so the model might be useful to have.


Best regards,
Heinrich Apfelmus

--
http://apfelmus.nfshost.com




More information about the Haskell-Cafe mailing list