import Test.QuickCheck
{- Q1
Aims to test whether you understand list comprehensions,
recursion, and guards. It also assumes that you know standard function elem.
-}
q2 :: Eq a => [a] -> [a]
q2 [] = []
q2 (x:xs) | x `elem` xs = q2 [y | y <- xs, y /= x]
| otherwise = x : q2 xs
-- q2 computes the list of unique items in the list.
-- You only need to write the answer ["eggs","chips"]
-- Here are the steps (NOT required!)
prop_answer = all (== a)
[
q2 ["spam","eggs","chips","spam"]
,q2 [y | y <- ["eggs","chips","spam"], y /= "spam"]
,q2 ["eggs","chips"]
,"eggs" : q2 ["chips"]
,"eggs" : "chips" : q2 []
,["eggs","chips"]
]
where a = q2 ( words "spam eggs chips spam")
----------------------
-- This question tests that you can write a recursive function
-- over numbers.
type WeekNumber = Int
rainfall :: WeekNumber -> Double -- assume this function exists
rainfall = undefined
mostRain :: WeekNumber -> Double
mostRain n | n < 1 = 0
| otherwise = max (rainfall n) (mostRain (n-1))
------------------
{-
This function tests that you can understand a
data type definition and write a definition using pattern matching
-}
data Suit = Hearts | Clubs | Diamonds | Spades
deriving Eq
data Rank = Numeric Int | Jack | Queen | King | Ace
deriving Eq
data Card = NormalCard Rank Suit | Joker -- different from lab 2
deriving Eq
countAces:: [Card] -> Int
countAces [] = 0
countAces (c : cs) = countCard c + countAces cs
where countCard Joker = 1
countCard (NormalCard Ace _) = 1
countCard _ = 0
-----------------
{-
This tests that you can write a recursive definition
over a recursive data type
-}
data Expr = Num Double | BinOp Op Expr Expr
deriving (Eq,Show)
data Op = Add | Mul
deriving (Eq,Show)
countOp :: Op -> Expr -> Int
countOp op (BinOp op' e1 e2)
| op == op' = 1 + rest
| otherwise = rest
where rest = countOp op e1 + countOp op e2
countOp _ _ = 0
---------
{-
This tests that you understand the relation between map, filter and list comprehensions, and that you can write this as a property
-}
prop_map_filter f p xs =
map f (filter p xs) == [f x | x <- xs, p x]
---------
{-
This tests that you can take similar definitions and turn them into a single more general definition, in this case by making a higher order function.
-}
bf,df :: [Int] -> [Int]
bf [] = []
bf [x] = [abs x]
bf (x:y:xs) = (abs x) : y : bf xs
df [] = []
df [x] = [x + 1]
df (x:y:xs) = (x + 1) : y : df xs
prop_gf xs = bf xs == gf abs xs
&& df xs == gf (+1) xs
gf :: (a -> a) -> [a] -> [a]
gf h [] = []
gf h [x] = [h x]
gf h (x:y:xs) = (h x) : y : gf h xs
----------------
{-
This tests that you can use do notation to write simple instructions, in this case for Gen (quickCheck generators).
-}
luckyList :: Gen [Integer]
luckyList = do
front <- arbitrary
back <- arbitrary
return (front ++ [7] ++ back)