{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Array.Properties where import Array import Array.ShowInstances import Array.EqInstances import Test.QuickCheck import Control.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 testL1Int = quickCheck (prop_L1 :: [Int] -> Property) testL1Pair = quickCheck (prop_L1 :: [(Int,Int)] -> Property) testL1Nest = quickCheck (prop_L1 :: [Array Int] -> Property) prop_L2 :: (ArrayElem a, Eq a) => [a] -> Bool prop_L2 xs = toList (fromList xs) == xs testL2Int = quickCheck (prop_L2 :: [Int] -> Bool) testL2Pair = quickCheck (prop_L2 :: [(Int,Int)] -> Bool) testL2Nest = 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 testL3Int = q (prop_L3 :: [Int] -> (Index, Size) -> Bool) testL3Pair = q (prop_L3 :: [(Int,Int)] -> (Index, Size) -> Bool) testL3Nest = 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_ [ testL1Int, testL1Pair, testL1Nest , testL2Int, testL2Pair, testL2Nest , testL3Int, testL3Pair, testL3Nest ] {- An earlier version had *Array.Properties> testL3Nest *** 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 :: (Eq b, Num b) => [(b, b)] -> Bool prop_invariant iss = is == init is' where (is, ns) = unzip iss is' = scanl (+) 0 ns