smallcheck-0.2.1: examples/listy/ListProps.hs
------------------------------------------------
-- Properties (some valid some invalid) of a few
-- standard list-processing functions.
-- A test module for SmallCheck.
-- Colin Runciman, August 2006.
-- Revised for 0.2, November 2006.
------------------------------------------------
module ListProps where
import Test.SmallCheck
-- properties about higher-order functions
-- plausible-looking but invalid laws about folds
prop_fold1 :: [Bool] -> Property
prop_fold1 xs =
not (null xs) ==>
\f -> foldl1 f xs == foldr1 f xs
prop_fold2 :: [Bool] -> [Bool] -> Property
prop_fold2 xs ys =
not (null xs) && not (null ys) ==>
\f -> foldr1 f xs `f` foldr1 f ys == foldr1 f (xs++ys)
-- properties using 'exists' with data and functional arguments
-- invalid because depth-bound for zs same as for xs ys
prop_union1 :: [Bool] -> [Bool] -> Property
prop_union1 xs ys =
exists $ \zs ->
\b -> (b `elem` zs) == (b `elem` xs || b `elem` ys)
-- valid variant: depth-bound doubled in existential
prop_union2 :: [Bool] -> [Bool] -> Property
prop_union2 xs ys =
existsDeeperBy (*2) $ \zs ->
\b -> (b `elem` zs) == (b `elem` xs || b `elem` ys)
-- do magical span arguments exist?
prop_span1 :: [Bool] -> [Bool] -> [Bool] -> Property
prop_span1 xs ys zs =
xs++ys == zs ==> exists $ \t -> (xs,ys) == span t zs
-- deliberate mistake in final isPrefix equation
isPrefix :: Ord a => [a] -> [a] -> Bool
isPrefix [] ys = True
isPrefix (x:xs) [] = False
isPrefix (x:xs) (y:ys) = x==y || isPrefix xs ys
-- this completeness property still holds
isPrefixComplete :: String -> String -> Bool
isPrefixComplete xs ys =
isPrefix xs (xs ++ ys)
-- but this existential soundness property fails
isPrefixSound :: String -> String -> Property
isPrefixSound xs ys = isPrefix xs ys ==>
exists $ \xs' -> ys == (xs ++ xs')
main :: IO ()
main = do
test1 "\\xs -> not (null xs) ==>\n\
\ \\f -> foldl1 f xs == foldr1 f xs ?"
prop_fold1
test1 "\\xs ys -> not (null xs) && not (null ys) ==>\n \
\ \\f -> foldr1 f xs `f` foldr1 f ys == foldr1 f (xs++ys) ?"
prop_fold2
test1 "\\xs ys -> exists $ \\zs ->\n\
\ \\b -> (b `elem` zs) == (b `elem` xs || b `elem` ys) ?"
prop_union1
test1 "\\xs ys -> existsDeeperBy (*2) $ \\zs ->\n\
\ \\b -> (b `elem` zs) == (b `elem` xs || b `elem` ys) ?"
prop_union2
test1 "\\xs ys zs -> xs++ys==zs ==>\n\
\ exists $ \\t -> (xs,ys) == span t zs ?"
prop_span1
test1 "\\xs ys -> isPrefix xs (xs++ys) ?"
isPrefixComplete
test1 "\\xs ys zs -> isPrefix xs ys ==>\n\
\ exists $ \\xs' -> ys == xs ++ xs' ?"
isPrefixSound
test1 :: Testable a => String -> a -> IO ()
test1 s t = do
rule
putStrLn s
rule
smallCheck 4 t
where
rule = putStrLn "----------------------------------------------------"