[Haskell] ANN: quickcheck-poly - Automating QuickCheck for polymorphic/overloaded properties in a small world of types

Ahn, Ki Yung kyagrd at gmail.com
Fri Oct 23 02:49:50 EDT 2009


Often times QuickCheck properties are polymophic/overloaded without
giving a monomorphic type signature.  But there can be several types
that you are interested.  You can write scripts that check all the types
you are interested annotating the generic property for each different
monotype, which is a tedious work to do.  Here, I automated this via
hint (a Haskell Interpreter Library).  How it works is it first asks a
type of a property to the Haskell interpreter and gets a type string,
identifies type variables that start with lowercase alphabet, generate
all possible substitution that may or may not be a correct type, stick
the type string to the property name as a signature and collect only the
meaningful types, and then finally run quickCheck over each meaningful
types.  The example below clearly illustrates what it does.

P.S. If there is a way to work this out without hint and string
manipulation I would be happy to hear that.  I've tried template haskell
but didn't work since you cannot test whether given type is correct or
instance of some class; it should be correct in the first place, no way
to recover from failure of type checking.


import Test.QuickCheck.PolyQC

import Prop -- the module that defiens the properties p0, p1, p2, p3, p4
 -- p0 x = x == x
 -- p1 x y z = x + (y + z) == (x + y) + z
 -- p2 x y = x + y == y + x
 -- p3 x = x == negate (negate x)
 -- p4 p = (fst p, snd p) == p

main = do putStrLn "testing p0 ======================================="
          print =<< polyQuickCheck' "Prop" "p0" ["Bool","Int","Double"]
          putStrLn "testing p1 ======================================="
          print =<< polyQuickCheck' "Prop" "p1" ["Bool","Int","Double"]
          putStrLn "testing p2 ======================================="
          print =<< polyQuickCheck' "Prop" "p2" ["Bool","Int","Double"]
          putStrLn "testing p3 ======================================="
          print =<< polyQuickCheck' "Prop" "p3" ["Bool","Int","Double"]
          putStrLn "testing p4 ======================================="
          print =<< polyQuickCheck' "Prop" "p4" ["Bool","Int","Double"]
          return ()

{-

*Main> :t p0
p0 :: (Eq a) => a -> Bool
*Main> :t p1
p1 :: (Num a) => a -> a -> a -> Bool
*Main> :t p2
p2 :: (Num a) => a -> a -> Bool
*Main> :t p3
p3 :: (Num a) => a -> Bool
*Main> :t p4
p4 :: (Eq a, Eq b) => (a, b) -> Bool
*Main> main
testing p0 =======================================
Right ["(\"(Eq Bool) => Bool -> Bool\",+++ OK, passed 100 tests.
())","(\"(Eq Int) => Int -> Bool\",+++ OK, passed 100 tests.
())","(\"(Eq Double) => Double -> Bool\",+++ OK, passed 100 tests.
())"]
testing p1 =======================================
Right ["(\"(Num Int) => Int -> Int -> Int -> Bool\",+++ OK, passed 100
tests.
())","(\"(Num Double) => Double -> Double -> Double -> Bool\",***
Failed! Falsifiable (after 9 tests and 2 shrinks):
4.0
-26.0
8.777291602197652
())"]
testing p2 =======================================
Right ["(\"(Num Int) => Int -> Int -> Bool\",+++ OK, passed 100 tests.
())","(\"(Num Double) => Double -> Double -> Bool\",+++ OK, passed 100
tests.
())"]
testing p3 =======================================
Right ["(\"(Num Int) => Int -> Bool\",+++ OK, passed 100 tests.
())","(\"(Num Double) => Double -> Bool\",+++ OK, passed 100 tests.
())"]
testing p4 =======================================
Right ["(\"(Eq Bool, Eq Bool) => (Bool, Bool) -> Bool\",+++ OK, passed
100 tests.
())","(\"(Eq Bool, Eq Int) => (Bool, Int) -> Bool\",+++ OK, passed 100
tests.
())","(\"(Eq Bool, Eq Double) => (Bool, Double) -> Bool\",+++ OK, passed
100 tests.
())","(\"(Eq Int, Eq Bool) => (Int, Bool) -> Bool\",+++ OK, passed 100
tests.
())","(\"(Eq Int, Eq Int) => (Int, Int) -> Bool\",+++ OK, passed 100 tests.
())","(\"(Eq Int, Eq Double) => (Int, Double) -> Bool\",+++ OK, passed
100 tests.
())","(\"(Eq Double, Eq Bool) => (Double, Bool) -> Bool\",+++ OK, passed
100 tests.
())","(\"(Eq Double, Eq Int) => (Double, Int) -> Bool\",+++ OK, passed
100 tests.
())","(\"(Eq Double, Eq Double) => (Double, Double) -> Bool\",+++ OK,
passed 100 tests.
())"]

-}



More information about the Haskell mailing list