-- sample solutions for Inf1-FP Revision Tutorial 5, week of 4-8 Nov 2013
import Char
import Test.QuickCheck
-- Question 1
-- 1a
f1 :: [String] -> String
f1 xs = concat [ x | x <- xs, not (null x), isUpper (head x) ]
-- 1b
g1 :: [String] -> String
g1 [] = ""
g1 (x:xs) | not (null x) && isUpper (head x) = x ++ g1 xs
| otherwise = g1 xs
test1 =
f1 ["This","Is","not","A","non","Test"] == "ThisIsATest" &&
f1 ["noThing","beGins","uPPER"] == "" &&
f1 ["Non-words","like","42","get","Dropped"] == "Non-wordsDropped" &&
f1 ["An","Empty","Word","","gets","dropped"] == "AnEmptyWord"
prop_1 :: [String] -> Bool
prop_1 xs = f1 xs == g1 xs
-- Question 2
-- 2a
isVowel x =
x == 'a' || x == 'e' || x == 'i' || x == 'o' || x == 'u' ||
x == 'A' || x == 'E' || x == 'I' || x == 'O' || x == 'U'
f2 :: String -> Bool
f2 xs = and [ isUpper x | x <- xs, isVowel x]
-- 2b
g2 :: String -> Bool
g2 [] = True
g2 (x:xs) | isVowel x = isUpper x && g2 xs
| otherwise = g2 xs
-- 2c
h2 :: String -> Bool
h2 xs = foldr (&&) True (map isUpper (filter isVowel xs))
test2 =
f2 "ALL CAPS" == True &&
f2 "r3cURsI0n" == True &&
f2 [] == True &&
f2 "normal text" == False
prop_2 :: String -> Bool
prop_2 xs = f2 xs == g2 xs && g2 xs == h2 xs
-- Question 3
-- 3a
isSmallDigit x = digitToInt x >= 5
f3 :: String -> Bool
f3 xs = and [ isSmallDigit x | x <- xs, isDigit x]
-- 3b
g3 :: String -> Bool
g3 [] = True
g3 (x:xs) | isDigit x = isSmallDigit x && g3 xs
| otherwise = g3 xs
-- 3c
h3 :: String -> Bool
h3 xs = foldr (&&) True (map isSmallDigit (filter isDigit xs))
test3 =
f3 "normal text" == True &&
f3 "number 75" == True &&
f3 "" == True &&
f3 "17 is a prime" == False
prop_3 :: String -> Bool
prop_3 xs = f3 xs == g3 xs && g3 xs == h3 xs
-- Question 4
isPunctuation x = not (isAlpha x || isDigit x)
-- 4a
f4 :: String -> Bool
f4 xs = and [ x == ' ' | x <- xs, isPunctuation x ]
-- 4a, alternative answer
f4' :: String -> Bool
f4' xs = and [ isAlpha x || isDigit x || x == ' ' | x <- xs ]
-- 4b
g4 :: String -> Bool
g4 [] = True
g4 (x:xs) | isPunctuation x = x == ' ' && g4 xs
| otherwise = g4 xs
-- 4c
h4 :: String -> Bool
h4 = foldr (&&) True . map (== ' ') . filter isPunctuation
test4 =
f4 "Just two spaces" == True &&
f4 "No other punctuation, period." == False &&
f4 "No exclamations!" == False &&
f4 "What the @#$!?" == False &&
f4 "l3tt3rs and d1g1ts 0k" == True &&
f4 "NoSpacesAtAllOK" == True &&
f4 "" == True
prop_4 :: String -> Bool
prop_4 xs = f4 xs == f4' xs && f4' xs == g4 xs && g4 xs == h4 xs
-- Question 5
-- 5a
f5 :: String -> Bool
f5 xs = and [ even (digitToInt x) | x <- xs, isDigit x ]
-- 5b
g5 :: String -> Bool
g5 [] = True
g5 (x:xs) | isDigit x = even (digitToInt x) && g5 xs
| otherwise = g5 xs
-- 5c
h5 :: String -> Bool
h5 xs = foldr (&&) True (map even (map digitToInt (filter isDigit xs)))
test5 =
f5 "246" == True &&
f5 "2467" == False &&
f5 "x4y2z" == True &&
f5 "abc12" == False
prop_5 :: String -> Bool
prop_5 xs = f5 xs == g5 xs && g5 xs == h5 xs