1
votes

I'm trying to learn QuickCheck and understand how it works. The data type of the quickCheck function is

quickCheck :: Testable prop => prop -> IO ()

On the other hand I have a function

prop_rev_involutive:Eq a => [a] -> Bool
prop_rev_involutive l = (reverse $ reverse l) == l

that I'm using for input for quickCheck. Running quickCheck prop_rev_involutive works fine but I don't understand how the types are matching.

is the type [a] -> Bool considered to be Testable? Why is this?

1
Hint: look at the instances for Testable. Also, remember to think about type defaulting.Joseph Sible-Reinstate Monica

1 Answers

1
votes

Testable is a type class - essentially an abstraction over things that can be turned into an automated test. The type class has several instances, one of which is Bool:

Testable Bool

That's not the type of prop_rev_involutive, though. Another instance of Testable is:

(Arbitrary a, Show a, Testable prop) => Testable (a -> prop)

This declares that for any a which is an instance of both Arbitrary and Show, a function from a to prop is itself Testable. We've already established that Bool is a Testable instance, so now you need to investigate whether [a] is an Arbitrary and Show instance.

The Arbitrary type class has a ton of instances, one of which is:

Arbitrary a => Arbitrary [a]

This declares that if a is an Arbitrary instance, then so is [a]. So, is a an Arbitrary instance? That depends on which concrete type you actually run quickCheck with. Some Haskell environments default to certain types (e.g. Int, which is an Arbitrary instance).

You'll need to go through the same line of reasoning for the Show type class.

I don't think that any unconstrained function [a] -> Bool is a Testable instance, but something like (Arbitrary a, Show a) => [a] -> Bool is. Examples include [Int] -> Bool and [Char] -> Bool. This is because Bool is Testable, and Int and Char are both Arbitrary and Show instances.