1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
|
{-# LANGUAGE ScopedTypeVariables, TemplateHaskell #-}
module Main where
--------------------------------------------------------------------------
-- imports
import Test.QuickCheck
import Text.Show.Functions
import Data.List
( sort
, group
, nub
, (\\)
)
import Control.Monad
( liftM
, liftM2
)
import Data.Maybe
--import Text.Show.Functions
--------------------------------------------------------------------------
-- binary search trees
data Set a
= Node a (Set a) (Set a)
| Empty
deriving ( Eq, Ord, Show )
empty :: Set a
empty = Empty
isEmpty :: Set a -> Bool
isEmpty Empty = True
isEmpty _ = False
unit :: a -> Set a
unit x = Node x empty empty
size :: Set a -> Int
size Empty = 0
size (Node _ s1 s2) = 1 + size s1 + size s2
insert :: Ord a => a -> Set a -> Set a
insert x s = s `union` unit x
merge :: Set a -> Set a -> Set a
s `merge` Empty = s
s `merge` Node x Empty s2 = Node x s s2
s `merge` Node x (Node y s11 s12) s2 = Node y s (Node x (s11 `merge` s12) s2)
delete :: Ord a => a -> Set a -> Set a
delete x Empty = Empty
delete x (Node x' s1 s2) =
case x `compare` x' of
LT -> Node x' (delete x s1) s2
EQ -> s1 `merge` s2
GT -> Node x' s1 (delete x s2)
union :: Ord a => Set a -> Set a -> Set a
{-
s1 `union` Empty = s1
Empty `union` s2 = s2
s1@(Node x s11 s12) `union` s2@(Node y s21 s22) =
case x `compare` y of
LT -> Node x s11 (s12 `union` Node y Empty s22) `union` s21
EQ -> Node x (s11 `union` s21) (s12 `union` s22)
--GT -> s11 `union` Node y s21 (Node x Empty s12 `union` s22)
GT -> Node x (s11 `union` Node y s21 Empty) s12 `union` s22
-}
s1 `union` Empty = s1
Empty `union` s2 = s2
Node x s11 s12 `union` s2 = Node x (s11 `union` s21) (s12 `union` s22)
where
(s21,s22) = split x s2
split :: Ord a => a -> Set a -> (Set a, Set a)
split x Empty = (Empty, Empty)
split x (Node y s1 s2) =
case x `compare` y of
LT -> (s11, Node y s12 s2)
EQ -> (s1, s2)
GT -> (Node y s1 s21, s22)
where
(s11,s12) = split x s1
(s21,s22) = split x s2
mapp :: (a -> b) -> Set a -> Set b
mapp f Empty = Empty
mapp f (Node x s1 s2) = Node (f x) (mapp f s1) (mapp f s2)
fromList :: Ord a => [a] -> Set a
--fromList xs = build [ (empty,x) | x <- sort xs ]
fromList xs = build [ (empty,head x) | x <- group (sort xs) ]
where
build [] = empty
build [(s,x)] = attach x s
build sxs = build (sweep sxs)
sweep [] = []
sweep [sx] = [sx]
sweep ((s1,x1):(s2,x2):sxs) = (Node x1 s1 s2,x2) : sweep sxs
attach x Empty = unit x
attach x (Node y s1 s2) = Node y s1 (attach x s2)
toList :: Set a -> [a]
toList s = toSortedList s
toSortedList :: Set a -> [a]
toSortedList s = toList' s []
where
toList' Empty xs = xs
toList' (Node x s1 s2) xs = toList' s1 (x : toList' s2 xs)
--------------------------------------------------------------------------
-- generators
instance (Ord a, Arbitrary a) => Arbitrary (Set a) where
arbitrary = sized (arbSet Nothing Nothing)
where
arbSet mx my n =
frequency $
[ (1, return Empty) ] ++
[ (7, do mz <- arbitrary `suchThatMaybe` (isOK mx my)
case mz of
Nothing -> return Empty
Just z -> liftM2 (Node z) (arbSet mx mz n2)
(arbSet mz my n2)
where n2 = n `div` 2)
| n > 0
]
isOK mx my z =
maybe True (<z) mx && maybe True (z<) my
shrink Empty = []
shrink t@(Node x s1 s2) = [ s1, s2 ]
++ [ t' | x' <- shrink x, let t' = Node x' s1 s2, invariant t' ]
-- instance (Ord a, ShrinkSub a) => ShrinkSub (Set a)
--------------------------------------------------------------------------
-- properties
(.<) :: Ord a => Set a -> a -> Bool
Empty .< x = True
Node y _ s .< x = y < x && s .< x
(<.) :: Ord a => a -> Set a -> Bool
x <. Empty = True
x <. Node y _ s = x < y && x <. s
(==?) :: Ord a => Set a -> [a] -> Bool
s ==? xs = invariant s && sort (toList s) == nub (sort xs)
invariant :: Ord a => Set a -> Bool
invariant Empty = True
invariant (Node x s1 s2) = s1 .< x && x <. s2 && invariant s1 && invariant s2
prop_Invariant (s :: Set Int) =
invariant s
prop_Empty =
empty ==? ([] :: [Int])
prop_Unit (x :: Int) =
unit x ==? [x]
prop_Size (s :: Set Int) =
cover 60 (size s >= 15) "large" $
size s == length (toList s)
prop_Insert x (s :: Set Int) =
insert x s ==? (x : toList s)
prop_Delete x (s :: Set Int) =
delete x s ==? (toList s \\ [x])
prop_Union s1 (s2 :: Set Int) =
(s1 `union` s2) ==? (toList s1 ++ toList s2)
prop_Mapp (f :: Int -> Int) (s :: Set Int) =
expectFailure $
whenFail (putStrLn ("Fun: " ++ show [ (x,f x) | x <- toList s])) $
mapp f s ==? map f (toList s)
prop_FromList (xs :: [Int]) =
fromList xs ==? xs
prop_ToSortedList (s :: Set Int) =
s ==? xs && xs == sort xs
where
xs = toSortedList s
-- whenFail (putStrLn ("Result: " ++ show (fromList xs))) $
prop_FromList' (xs :: [Int]) =
shrinking shrink xs $ \xs' ->
fromList xs ==? xs
--------------------------------------------------------------------------
-- main
return []
main = $quickCheckAll
--------------------------------------------------------------------------
-- the end.
|