-- Informatics 1 - Functional Programming
-- Class Test 2012
--
-- Sample solutions
-- I would not expect you to include the tests and use of QuickCheck
-- shown below in this exam, except for question 2(c) which explicitly
-- asks for a QuickCheck property, since you have no access to Haskell.
-- But this style of testing is highly recommended when you do have
-- Haskell access, for instance for tutorial exercises and the final exam.
import Data.Char
import Test.QuickCheck
-- Problem 1
-- a
f :: Char -> Bool
f x | 'a' <= x && x <= 'm' = True
| 'A' <= x && x <= 'M' = True
| 'n' <= x && x <= 'z' = False
| 'N' <= x && x <= 'Z' = False
test_f f =
f 'e' == True && f 'P' == False && f 'q' == False &&
f 'G' == True && f 'n' == False && f 'M' == True
test_1a = test_f f
-- b
g :: String -> Bool
g xs = length [ x | x <- xs, isAlpha x, f x ]
> length [ x | x <- xs, isAlpha x, not(f x) ]
test_g g =
g "SyzYGy" == False && g "aB7L!e" == True && g "" == False &&
g "Aardvark" == True && g "emnity" == False
test_1b = test_g g
-- c
h :: String -> Bool
h xs = count xs > 0
where
count [] = 0
count (x:xs) | isAlpha x && f x = count xs + 1
| isAlpha x && not(f x) = count xs - 1
| otherwise = count xs
test_1c = test_g h
prop_1c xs = all isAscii xs ==> g xs == h xs
-- Note: pre-condition isAscii xs is required because isAlpha x is also
-- True for non-ASCII Unicode alphabetic characters, and f is only
-- defined for ASCII. (I would not expect you to know this, and I would
-- not include this question on the final exam because of the chance that
-- you might waste time struggling with QuickCheck before figuring it out.)
-- c, alternative solution
h' :: String -> Bool
h' xs = countFirst xs > countLast xs
where
countFirst [] = 0
countFirst (x:xs) | isAlpha x && f x = countFirst xs + 1
| otherwise = countFirst xs
countLast [] = 0
countLast (x:xs) | isAlpha x && not(f x) = countLast xs + 1
| otherwise = countLast xs
test_1c' = test_g h'
prop_1c' xs = all isAscii xs ==> h xs == h' xs
test_1 = test_1a && test_1b && test_1c && test_1c'
-- Problem 2
-- a
c :: [Int] -> [Int]
c (x:xs) = [ x | (x,y) <- zip (x:xs) xs, x == y ]
test_c c =
c [3,1,1,3,3,5] == [1,3] && c [2,1,4,1,2] == [] &&
c [4,1,1,1,4,4] == [1,1,4] && c [3,3,1,3,1] == [3] &&
c [2,2,2,2,2] == [2,2,2,2] && c [42] == []
test_2a = test_c c
-- b
d :: [Int] -> [Int]
d [x] = []
d (x:y:zs) | x==y = x : d (y:zs)
| otherwise = d (y:zs)
test_2b = test_c d
-- c
prop_cd :: [Int] -> Bool
prop_cd xs = null xs || c xs == d xs
test_2 = test_2a && test_2b
-- testing everything
test = test_1 && test_2
main =
print test >>
quickCheck prop_1c >>
quickCheck prop_1c' >>
quickCheck prop_cd