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)