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