Hello Haskell Café,

A new version of LeanCheck is out (v0.8.0). LeanCheck is a property testing library (like QuickCheck) that tests values enumeratively.

Whats new? Among several changes, the most notable and significant are:

LeanCheck’s changelog provides more details.

Take for example the following higher-order property that takes a functional argument and states an equivalence between foldl and foldr:

prop_foldlr' :: (Int->Int->Int) -> Int -> [Int] -> Bool
prop_foldlr' f z xs  =  foldl (flip f) z (reverse xs) == foldr f z xs

You can check that it is correct by:

> import Test.LeanCheck
> import Test.LeanCheck.Function
> check prop_foldlr'
+++ OK, passed 200 tests.

Now here is an incorrect version of the above property:

prop_foldlr :: (A -> A -> A) -> A -> [A] -> Bool
prop_foldlr f z xs  =  foldr f z xs == foldl f z xs

You can check that it is incorrect by:

> check prop_foldlr
*** Failed! Falsifiable (after 75 tests):
\x _ -> case x of
        0 -> 1
        _ -> 0
0
[0,0]

LeanCheck reports the smallest counterexample it finds. The functional argument is now reported very concisely: a function that returns 1 whenever the first argument is 0 and returns 0 otherwise.

Here’s one last incorrect example property with two functional arguments:

prop_mapFilter :: (Int->Int) -> (Int->Bool) -> [Int] -> Bool
prop_mapFilter f p xs  =  filter p (map f xs) == map f (filter p xs)

> check prop_mapFilter
*** Failed! Falsifiable (after 36 tests):
\_ -> 0
\x -> case x of
      0 -> True
      _ -> False
[1]

The functions map and filter do not commute, the three values above are a counterexample.

You can find LeanCheck on Hackage or GitHub. As usual, you can install it with:

$ cabal install leancheck