quickspec-0.9: examples/Heaps.hs
{-# LANGUAGE ScopedTypeVariables,DeriveDataTypeable #-}
import Prelude hiding (null)
import Test.QuickSpec
import Test.QuickCheck
import Data.Typeable
import Data.Ord
import qualified Data.List as L
data Heap a = Nil | Branch Int a (Heap a) (Heap a) deriving Typeable
instance Ord a => Eq (Heap a) where
h1 == h2 = toList h1 == toList h2
instance Ord a => Ord (Heap a) where
compare = comparing toList
instance (Ord a, Arbitrary a) => Arbitrary (Heap a) where
arbitrary = fmap fromList arbitrary
toList :: Ord a => Heap a -> [a]
toList h | null h = []
| otherwise = findMin h:toList (deleteMin h)
fromList :: Ord a => [a] -> Heap a
fromList = foldr insert Nil
null :: Heap a -> Bool
null Nil = True
null _ = False
findMin :: Heap a -> a
findMin (Branch _ x _ _) = x
insert :: Ord a => a -> Heap a -> Heap a
insert x h = merge h (branch x Nil Nil)
deleteMin :: Ord a => Heap a -> Heap a
deleteMin (Branch _ _ l r) = merge l r
branch :: Ord a => a -> Heap a -> Heap a -> Heap a
branch x l r | npl l <= npl r = Branch (npl l + 1) x l r
| otherwise = Branch (npl r + 1) x r l
merge :: Ord a => Heap a -> Heap a -> Heap a
merge Nil h = h
merge h Nil = h
merge h1@(Branch _ x1 l1 r1) h2@(Branch _ x2 l2 r2)
| x1 <= x2 = branch x1 (merge l1 h2) r1
| otherwise = merge h2 h1
npl :: Heap a -> Int
npl Nil = 0
npl (Branch n _ _ _) = n
mergeLists :: Ord a => [a] -> [a] -> [a]
mergeLists [] xs = xs
mergeLists xs [] = xs
mergeLists (x:xs) (y:ys)
| x < y = x:mergeLists xs (y:ys)
| otherwise = y:mergeLists (x:xs) ys
heaps :: forall a. (Ord a, Typeable a, Arbitrary a) => a -> [Sig]
heaps a = [
prelude a,
["h", "h1", "h2"] `vars` (undefined :: Heap a),
"nil" `fun0` (Nil :: Heap a),
"insert" `fun2` (insert :: a -> Heap a -> Heap a),
"findMin" `fun1` (findMin :: Heap a -> a),
"deleteMin" `fun1` (deleteMin :: Heap a -> Heap a),
"merge" `fun2` (merge :: Heap a -> Heap a -> Heap a),
"null" `fun1` (null :: Heap a -> Bool),
"toList" `fun1` (toList :: Heap a -> [a]),
"fromList" `fun1` (fromList :: [a] -> Heap a),
-- A few more list functions that are helpful for getting
-- laws about toList/fromList.
-- We use "background" to mark the functions as background theory,
-- so that we only get laws that involve one of the heap functions.
background [
"sort" `fun1` (L.sort :: [a] -> [a]),
"insertList" `fun2` (L.insert :: a -> [a] -> [a]),
"nullList" `fun1` (L.null :: [a] -> Bool),
"deleteList" `fun2` (L.delete :: a -> [a] -> [a]),
"mergeLists" `fun2` (mergeLists :: [a] -> [a] -> [a])]]
main = quickSpec (heaps (undefined :: A))