Blame examples/Set.hs

Packit 1d8052
{-# LANGUAGE ScopedTypeVariables, TemplateHaskell #-}
Packit 1d8052
module Main where
Packit 1d8052
Packit 1d8052
--------------------------------------------------------------------------
Packit 1d8052
-- imports
Packit 1d8052
Packit 1d8052
import Test.QuickCheck
Packit 1d8052
Packit 1d8052
import Text.Show.Functions
Packit 1d8052
import Data.List
Packit 1d8052
  ( sort
Packit 1d8052
  , group
Packit 1d8052
  , nub
Packit 1d8052
  , (\\)
Packit 1d8052
  )
Packit 1d8052
Packit 1d8052
import Control.Monad
Packit 1d8052
  ( liftM
Packit 1d8052
  , liftM2
Packit 1d8052
  )
Packit 1d8052
Packit 1d8052
import Data.Maybe
Packit 1d8052
Packit 1d8052
--import Text.Show.Functions
Packit 1d8052
Packit 1d8052
--------------------------------------------------------------------------
Packit 1d8052
-- binary search trees
Packit 1d8052
Packit 1d8052
data Set a
Packit 1d8052
  = Node a (Set a) (Set a)
Packit 1d8052
  | Empty
Packit 1d8052
 deriving ( Eq, Ord, Show )
Packit 1d8052
Packit 1d8052
empty :: Set a
Packit 1d8052
empty = Empty
Packit 1d8052
Packit 1d8052
isEmpty :: Set a -> Bool
Packit 1d8052
isEmpty Empty = True
Packit 1d8052
isEmpty _     = False
Packit 1d8052
Packit 1d8052
unit :: a -> Set a
Packit 1d8052
unit x = Node x empty empty
Packit 1d8052
Packit 1d8052
size :: Set a -> Int
Packit 1d8052
size Empty          = 0
Packit 1d8052
size (Node _ s1 s2) = 1 + size s1 + size s2
Packit 1d8052
Packit 1d8052
insert :: Ord a => a -> Set a -> Set a
Packit 1d8052
insert x s = s `union` unit x
Packit 1d8052
Packit 1d8052
merge :: Set a -> Set a -> Set a
Packit 1d8052
s `merge` Empty                      = s
Packit 1d8052
s `merge` Node x Empty s2            = Node x s s2
Packit 1d8052
s `merge` Node x (Node y s11 s12) s2 = Node y s (Node x (s11 `merge` s12) s2)
Packit 1d8052
Packit 1d8052
delete :: Ord a => a -> Set a -> Set a
Packit 1d8052
delete x Empty = Empty
Packit 1d8052
delete x (Node x' s1 s2) =
Packit 1d8052
  case x `compare` x' of
Packit 1d8052
    LT -> Node x' (delete x s1) s2
Packit 1d8052
    EQ -> s1 `merge` s2
Packit 1d8052
    GT -> Node x' s1 (delete x s2)
Packit 1d8052
Packit 1d8052
union :: Ord a => Set a -> Set a -> Set a
Packit 1d8052
{-
Packit 1d8052
s1    `union` Empty = s1
Packit 1d8052
Empty `union` s2    = s2
Packit 1d8052
s1@(Node x s11 s12) `union` s2@(Node y s21 s22) =
Packit 1d8052
  case x `compare` y of
Packit 1d8052
    LT -> Node x s11 (s12 `union` Node y Empty s22) `union` s21
Packit 1d8052
    EQ -> Node x (s11 `union` s21) (s12 `union` s22)
Packit 1d8052
    --GT -> s11 `union` Node y s21 (Node x Empty s12 `union` s22)
Packit 1d8052
    GT -> Node x (s11 `union` Node y s21 Empty) s12 `union` s22 
Packit 1d8052
-}
Packit 1d8052
s1             `union` Empty = s1
Packit 1d8052
Empty          `union` s2    = s2
Packit 1d8052
Node x s11 s12 `union` s2    = Node x (s11 `union` s21) (s12 `union` s22)
Packit 1d8052
 where
Packit 1d8052
  (s21,s22) = split x s2
Packit 1d8052
Packit 1d8052
split :: Ord a => a -> Set a -> (Set a, Set a)
Packit 1d8052
split x Empty = (Empty, Empty)
Packit 1d8052
split x (Node y s1 s2) =
Packit 1d8052
  case x `compare` y of
Packit 1d8052
    LT -> (s11, Node y s12 s2)
Packit 1d8052
    EQ -> (s1, s2)
Packit 1d8052
    GT -> (Node y s1 s21, s22)
Packit 1d8052
 where
Packit 1d8052
  (s11,s12) = split x s1
Packit 1d8052
  (s21,s22) = split x s2
Packit 1d8052
  
Packit 1d8052
mapp :: (a -> b) -> Set a -> Set b
Packit 1d8052
mapp f Empty          = Empty
Packit 1d8052
mapp f (Node x s1 s2) = Node (f x) (mapp f s1) (mapp f s2)
Packit 1d8052
Packit 1d8052
fromList :: Ord a => [a] -> Set a
Packit 1d8052
--fromList xs = build [ (empty,x) | x <- sort xs ]
Packit 1d8052
fromList xs = build [ (empty,head x) | x <- group (sort xs) ]
Packit 1d8052
 where
Packit 1d8052
  build []      = empty
Packit 1d8052
  build [(s,x)] = attach x s
Packit 1d8052
  build sxs     = build (sweep sxs)
Packit 1d8052
Packit 1d8052
  sweep []                    = []
Packit 1d8052
  sweep [sx]                  = [sx]
Packit 1d8052
  sweep ((s1,x1):(s2,x2):sxs) = (Node x1 s1 s2,x2) : sweep sxs
Packit 1d8052
Packit 1d8052
  attach x Empty          = unit x
Packit 1d8052
  attach x (Node y s1 s2) = Node y s1 (attach x s2)
Packit 1d8052
Packit 1d8052
toList :: Set a -> [a]
Packit 1d8052
toList s = toSortedList s
Packit 1d8052
Packit 1d8052
toSortedList :: Set a -> [a]
Packit 1d8052
toSortedList s = toList' s []
Packit 1d8052
 where
Packit 1d8052
  toList' Empty          xs = xs
Packit 1d8052
  toList' (Node x s1 s2) xs = toList' s1 (x : toList' s2 xs)
Packit 1d8052
Packit 1d8052
--------------------------------------------------------------------------
Packit 1d8052
-- generators
Packit 1d8052
Packit 1d8052
instance (Ord a, Arbitrary a) => Arbitrary (Set a) where
Packit 1d8052
  arbitrary = sized (arbSet Nothing Nothing)
Packit 1d8052
   where
Packit 1d8052
    arbSet mx my n =
Packit 1d8052
      frequency $
Packit 1d8052
        [ (1, return Empty) ] ++
Packit 1d8052
        [ (7, do mz <- arbitrary `suchThatMaybe` (isOK mx my)
Packit 1d8052
                 case mz of
Packit 1d8052
                   Nothing -> return Empty
Packit 1d8052
                   Just z  -> liftM2 (Node z) (arbSet mx mz n2)
Packit 1d8052
                                              (arbSet mz my n2)
Packit 1d8052
                    where n2 = n `div` 2)
Packit 1d8052
        | n > 0
Packit 1d8052
        ]
Packit 1d8052
Packit 1d8052
    isOK mx my z =
Packit 1d8052
      maybe True (
Packit 1d8052
Packit 1d8052
  shrink Empty            = []
Packit 1d8052
  shrink t@(Node x s1 s2) = [ s1, s2 ]
Packit 1d8052
                         ++ [ t' | x' <- shrink x, let t' = Node x' s1 s2, invariant t' ]
Packit 1d8052
Packit 1d8052
-- instance (Ord a, ShrinkSub a) => ShrinkSub (Set a)
Packit 1d8052
Packit 1d8052
--------------------------------------------------------------------------
Packit 1d8052
-- properties
Packit 1d8052
Packit 1d8052
(.<) :: Ord a => Set a -> a -> Bool
Packit 1d8052
Empty      .< x = True
Packit 1d8052
Node y _ s .< x = y < x && s .< x
Packit 1d8052
Packit 1d8052
(<.) :: Ord a => a -> Set a -> Bool
Packit 1d8052
x <. Empty      = True
Packit 1d8052
x <. Node y _ s = x < y && x <. s
Packit 1d8052
Packit 1d8052
(==?) :: Ord a => Set a -> [a] -> Bool
Packit 1d8052
s ==? xs = invariant s && sort (toList s) == nub (sort xs)
Packit 1d8052
Packit 1d8052
invariant :: Ord a => Set a -> Bool
Packit 1d8052
invariant Empty          = True
Packit 1d8052
invariant (Node x s1 s2) = s1 .< x && x <. s2 && invariant s1 && invariant s2
Packit 1d8052
Packit 1d8052
prop_Invariant (s :: Set Int) =
Packit 1d8052
  invariant s
Packit 1d8052
Packit 1d8052
prop_Empty =
Packit 1d8052
  empty ==? ([] :: [Int])
Packit 1d8052
Packit 1d8052
prop_Unit (x :: Int) =
Packit 1d8052
  unit x ==? [x]
Packit 1d8052
Packit 1d8052
prop_Size (s :: Set Int) =
Packit 1d8052
  cover (size s >= 15) 60 "large" $
Packit 1d8052
    size s == length (toList s)
Packit 1d8052
Packit 1d8052
prop_Insert x (s :: Set Int) =
Packit 1d8052
  insert x s ==? (x : toList s)
Packit 1d8052
Packit 1d8052
prop_Delete x (s :: Set Int) =
Packit 1d8052
  delete x s ==? (toList s \\ [x])
Packit 1d8052
Packit 1d8052
prop_Union s1 (s2 :: Set Int) =
Packit 1d8052
  (s1 `union` s2) ==? (toList s1 ++ toList s2)
Packit 1d8052
Packit 1d8052
prop_Mapp (f :: Int -> Int) (s :: Set Int) =
Packit 1d8052
  expectFailure $
Packit 1d8052
    whenFail (putStrLn ("Fun: " ++ show [ (x,f x) | x <- toList s])) $
Packit 1d8052
      mapp f s ==? map f (toList s)
Packit 1d8052
Packit 1d8052
prop_FromList (xs :: [Int]) =
Packit 1d8052
  fromList xs ==? xs
Packit 1d8052
Packit 1d8052
prop_ToSortedList (s :: Set Int) =
Packit 1d8052
  s ==? xs && xs == sort xs
Packit 1d8052
 where
Packit 1d8052
  xs = toSortedList s
Packit 1d8052
  
Packit 1d8052
--  whenFail (putStrLn ("Result: " ++ show (fromList xs))) $
Packit 1d8052
Packit 1d8052
prop_FromList' (xs :: [Int]) =
Packit 1d8052
  shrinking shrink xs $ \xs' ->
Packit 1d8052
    fromList xs ==? xs
Packit 1d8052
Packit 1d8052
--------------------------------------------------------------------------
Packit 1d8052
-- main
Packit 1d8052
Packit 1d8052
return []
Packit 1d8052
main = $quickCheckAll
Packit 1d8052
Packit 1d8052
--------------------------------------------------------------------------
Packit 1d8052
-- the end.