Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any test-suite able to automatically choose a bunch of types and values that match the constraints?

In my journey to learn Haskell I'm re-implementing a lot of functions that already exist. I get my code to compile (which means that types check), but I'm not sure whether the behavior is correct.

QuickCheck and its limitation

I've been testing some simple functions with QuickCheck and that works well. However it feels limited with functions that are a bit more complex. For instance let's say that I re-implement liftA2. (This is just one random example. Forget that it's a method. Take any other function you like.)

-- my re-implementation of liftA2
liftA2' :: Applicative app => (a -> b -> c) -> app a -> app b -> app c
liftA2' f aa ab = f <$> aa <*> ab

I'd like to test whether it behaves exactly like liftA2 for some (ideally any) function f and Applicative instance app.

Doing this with QuickCheck requires choosing one function and one instance. Then I have to write a line similar to this:

-- test whether liftA2' behaves exactly like liftA2
-- ...only for the (,) function and [Int] instances :(
quickCheck $ \aa bb -> liftA2 (,) aa bb === liftA2' (,) (aa :: [Int]) (bb :: [Int])

But this feels pretty far from ideal: the thing I just wrote is more convoluted than the function itself and it tests my lift2A' against only one function (,) and only one type ([Int]).

What I'm looking for

I would love it if it were possible to write something like...

-- test whether liftA2' behaves exactly like liftA2
check $ liftA2 === liftA2'

and then let the test suite choose a bunch of types, functions and values to run some tests: ideally it should test various corner cases and reach 100% coverage (or warn me if it couldn't cover everything).

I believe that something like a GHC plugin should be able to do this, since it could see the type and the constraints of everything involved. But a module like QuickCheck can not.

Question:

Is there any testing suite for Haskell that is able to come up with types and values that match the types and type constraints?

like image 564
Blue Nebula Avatar asked Sep 19 '25 13:09

Blue Nebula


1 Answers

QuickCheck doesn't limit you to testing against only one function. Here's how you could test against arbitrary functions instead:

quickCheck $ \(Fn2 f) aa bb -> liftA2 f aa bb === liftA2' (f :: Int -> Int -> (Int,Int)) (aa :: [Int]) (bb :: [Int])

Unfortunately, I don't know of a way to get what you want for types too, although you can probably mitigate a lot of it by keeping parametricity in mind when you're choosing your types. For example, this would be a step in the right direction:

import Test.QuickCheck.Poly

quickCheck $ \(Fn2 f) aa bb -> liftA2 f aa bb === liftA2' (f :: A -> B -> C) (aa :: [A]) (bb :: [B])
like image 70
Joseph Sible-Reinstate Monica Avatar answered Sep 23 '25 00:09

Joseph Sible-Reinstate Monica