-- sample solutions for Inf1-FP Revision Tutorial 5

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

