# Lecture 12 — 2018-02-22

## QuickCheck

### Generators

``````import Test.QuickCheck
import System.Random

evenBelowTen :: Gen Int
evenBelowTen = elements [0,2,4,6,8]

fiveNums :: Gen [Int]
fiveNums = do
n1 <- evenBelowTen
n2 <- evenBelowTen
n3 <- evenBelowTen
n4 <- evenBelowTen
n5 <- evenBelowTen
return [n1,n2,n3,n4,n5]``````
``````data BST a = Empty | Node (BST a) a (BST a) deriving (Eq, Show)

bt :: Arbitrary a => Gen (BST a)
bt = oneof [return Empty,
Node <\$> bt <*> arbitrary <*> bt]``````
``````instance Arbitrary a =>  Arbitrary (BST a) where
arbitrary = bt``````

### Testing properties

Check out the `Testable` type class.

``````sums_ok :: Int -> Int -> Bool
sums_ok n1 n2 = n1 + n2 == n2 + n1``````
``````sums_ok = forAll (arbitrary :: (Int,Int)) \$ sum_ok
where sum_ok :: Int -> Int -> Bool
sum_ok (n1,n2) = n1 + n2 == n2 + n1``````

### Size-bounded binary trees

``````size :: BST a -> Int
size Empty = 0
size (Node l _ r) = 1 + size l + size r

sizedBT :: Arbitrary a => Int -> Gen (BST a)
sizedBT 0 = return Empty
sizedBT n = oneof
[return Empty,
Node <\$> sizedBT (n `div` 2)
<*> arbitrary
<*> sizedBT (n `div` 2)]

bt' :: Arbitrary a => Gen (BST a)
bt' = sized sizedBT

prop_nonnegative_size :: BST a -> Bool
prop_nonnegative_size t = size t > 0``````

### Generating BSTs

Here are the familiar BST operations.

``````insert x Empty = Node Empty x Empty
insert x (Node l y r) | x < y  = Node (insert x l) y r
| x == y = Node l x r
| x > y  = Node l y (insert x r)

delete x Empty = Empty
delete x (Node l y r)
| x < y  = Node (delete x l) y r
| x > y  = Node l y (delete x r)
| x == y = case (l,r) of
(Empty, _) -> r
(l, Empty) -> l
_          -> let (min, r') = deleteMin r in
Node l min r'
where deleteMin Empty = error "nope"
deleteMin (Node Empty x r) = (x,r)
deleteMin (Node l x r) =
let (min, l') = deleteMin l in
(min, Node l' x r)

find _ Empty = Nothing
find v (Node l x r)
| v < x  = v `find` l
| v == x = Just x
| v > x  = v `find` r``````

We can directly generate BSTs by keeping track of their bounds.

``````boundedBST :: (Ord a, Enum a, Random a) => a -> a -> Gen (BST a)
boundedBST lo hi
| hi < lo = return Empty -- critical case!!!
| otherwise =
oneof [return Empty,
do
v <- choose (lo,hi)
l <- boundedBST lo (pred v)
r <- boundedBST (succ v) hi
return (Node l v r)]

maybeBounded :: Ord a => Maybe a -> Maybe a -> a -> Bool
maybeBounded Nothing Nothing x = True
maybeBounded Nothing (Just upper) x = x < upper
maybeBounded (Just lower) Nothing x = lower < x
maybeBounded (Just lower) (Just upper) x = lower < x && x < upper

isBST' :: Ord a => Maybe a -> Maybe a -> BST a -> Bool
isBST' lower upper Empty = True
isBST' lower upper (Node l x r) =
maybeBounded lower upper x &&
isBST' lower (Just x) l &&
isBST' (Just x) upper r

isBST :: Ord a => BST a -> Bool
isBST t = isBST' Nothing Nothing t``````

One possible instance for `Arbitrary` BSTs:

``````instance (Ord a, Bounded a, Enum a, Random a) => Arbitrary (BST a) where
arbitrary = boundedBST minBound maxBound``````

But we can do better: just reuse our BST operations to generate them.

``````bsts :: (Arbitrary a, Ord a) => Gen (BST a)
bsts = do
vs <- listOf arbitrary
return \$ foldr insert Empty vs

instance (Arbitrary a, Ord a) => Arbitrary (BST a) where
arbitrary = bsts

prop_insertFind :: Int -> BST Int -> Bool
prop_insertFind x t = find x (insert x t) == Just x

prop_insertFind' :: Property
prop_insertFind' =
forAll arbitrary \$ \x ->
forAll bsts \$ \t ->
find x (insert x t) == Just (x::Int)``````