{-# LANGUAGE StandaloneDeriving, GeneralizedNewtypeDeriving #-} module Array.Properties where import Array import Array.ShowInstances import Array.EqInstances import Test.QuickCheck import Monad(liftM) prop_L1 :: (ArrayElem a, Eq a) => [a] -> Property prop_L1 xs = not (null xs) ==> forAll (choose (0, length xs - 1)) $ \i -> fromList xs ! (Index i) == xs !! i test_L1Int = quickCheck (prop_L1 :: [Int] -> Property) test_L1Pair = quickCheck (prop_L1 :: [(Int,Int)] -> Property) test_L1Nest = quickCheck (prop_L1 :: [Array Int] -> Property) prop_L2 :: (ArrayElem a, Eq a) => [a] -> Bool prop_L2 xs = toList (fromList xs) == xs test_L2Int = quickCheck (prop_L2 :: [Int] -> Bool) test_L2Pair = quickCheck (prop_L2 :: [(Int,Int)] -> Bool) test_L2Nest = quickCheck (prop_L2 :: [Array Int] -> Bool) sliceModel :: [a] -> (Index, Size) -> [a] sliceModel xs (Index i, Size n) = take n (drop i xs) toModel :: ArrayElem a => Array a -> [a] toModel = toList (~=) :: (ArrayElem a, Eq a) => [a] -> Array a -> Bool model ~= impl = model == toModel impl prop_L3 :: (ArrayElem a, Eq a) => [a] -> (Index, Size) -> Bool prop_L3 xs p = sliceModel xs p ~= slice (fromList xs) p q :: (Testable prop) => prop -> IO () q = quickCheck test_L3Int = q (prop_L3 :: [Int] -> (Index, Size) -> Bool) test_L3Pair = q (prop_L3 :: [(Int,Int)] -> (Index, Size) -> Bool) test_L3Nest = q (prop_L3 :: [Array Int] -> (Index, Size) -> Bool) instance (Arbitrary a, ArrayElem a) => Arbitrary (Array a) where arbitrary = liftM fromList arbitrary instance Arbitrary Index where -- no negative indices arbitrary = liftM Index $ sized (\n-> choose (0,n)) instance Arbitrary Size where -- no negative sizes arbitrary = liftM Size $ sized (\n-> choose (0,n)) main = sequence_ [ test_L1Int, test_L1Pair, test_L1Nest , test_L2Int, test_L2Pair, test_L2Nest , test_L3Int, test_L3Pair, test_L3Nest ] {- An earlier version had *Array.Properties> test_L3Nest *** Failed! Falsifiable (after 4 tests): [ArrInt [2],ArrInt [-1,-2,-1]] (Index 1,Size 1) The problem was that slice for nested arrays did not preserve the invariant that the ins :: Array (Index, Size) should satisfy. In fact, it would be more convenient if the full sum (the element dropped by init) was also stored. -} test1l :: [Array Int] test1l = [ArrInt [-2,0] ,ArrInt [],ArrInt [0]] test1a :: Array (Array Int) test1a = fromList test1l -- Untested code - partial solution to the exercise. prop_invariant :: (Num b) => [(b, b)] -> Bool prop_invariant iss = is == init is' where (is, ns) = unzip iss is' = scanl (+) 0 ns