Assignment 2 solutions

Test driver

-- Imports must appear before other functions
import Control.Monad.State
-- Test driver
main = flip execStateT (0,0) $ do
  -- Ex 1
  verify "slice1" [1,2,3] $ slice 3 6 [0,0,0,1,2,3,0,0,0]
  verify "slice2" []      $ slice 2 2 [1..4]
  verify "slice3" [3]     $ slice 2 3 [1..4]
  verify "slice4" [3,4]   $ slice 2 10 [1..4]
  verify "slice5" []      $ slice 10 15 [1..4]
  -- Ex 2
  verify "rotate1" []            $ rotate 0 ([] :: [Int])
  verify "rotate2" [3,4,5,1,2]   $ rotate 2 [1..5]
  verify "rotate3" "adabraabrac" $ rotate 5 "abracadabra"
  -- Ex 3
  verify "everyOther1" [1,3,5,7,9] $ everyOther [1..10]
  verify "everyOther2" ["Al","Ca"] $ everyOther ["Al", "Bo", "Ca"]
  verify "everyOther3" "uiest"     $ everyOther "university"
  verify "everyOther4" "tal"       $ everyOther "trail"
  verify "everyOther5" []          $ everyOther ([] :: [Int])
  verify "everyOther6" "a"         $ everyOther "a"
  -- Ex 4
  verify "countOccurs1" 1 $ countOccurences 5 [1..10]
  verify "countOccurs2" 4 $ countOccurences 5 [1,5,2,5,3,5,7,5]
  verify "countOccurs3" 5 $ countOccurences 'a' "abracadabra"
  verify "countOccurs4" 2 $ countOccurences 'o' "xylophone"
  -- Ex 5
  verify "insert1" [2,4,6,8,10,12,14] $ insertElem 10 4 [2,4,6,8,12,14]
  verify "insert2" "caramel"          $ insertElem 'a' 3 "carmel"
  verify "insert3" "Haskell"          $ insertElem 'H' 0 "askell"
  verify "insert4" "FP rocks!"        $ insertElem '!' 8 "FP rocks"
  verify "insert5" "FP rocks"         $ insertElem '!' 20 "FP rocks"
  -- Ex 6
  verify "divides1" False $ divides  7 3
  verify "divides2" True  $ divides 18 3
  verify "divides3" False $ divides 29 2
  verify "divides4" False $ divides 29 3
  verify "divides5" True  $ divides 27 3
  -- Ex 7
  verify "isPrime1"  False $ isPrime 27
  verify "isPrime2"  True  $ isPrime 29
  verify "isPrime3"  False $ isPrime 1
  verify "isPrime4"  True  $ isPrime 2
  verify "isPrime5"  True  $ isPrime 101
  verify "isPrime6"  False $ isPrime 105
  -- Ex 8
  verify "twinPrime1" True $ twinPrime 11
  verify "twinPrime2" False $ twinPrime 13
  verify "twinPrime3" [3,5,11,17,29,41,59,71] $ filter twinPrime [1..100]
  -- Done
  get >>= say . show
  where
    say = liftIO . putStrLn
    correct (k, n) = (k+1, n+1)
    incorrect (k, n) = (k, n+1)
    verify :: (Show a, Eq a) => String -> a -> a -> StateT (Int,Int) IO ()
    verify = verify' (==)
    verifyF = verify' (\x y -> abs(x-y) < 0.00001)
    verify' :: (Show a) => (a -> a -> Bool) -> String -> a -> a ->
              StateT (Int,Int) IO ()
    verify' eq tag expected actual
      | eq expected actual = do
          modify correct
          say $ " OK " ++ tag
      | otherwise = do
          modify incorrect
          say $ "ERR " ++ tag ++ ": expected " ++ show expected
            ++ " got " ++ show actual
-- End of test driver

Exercise 1

slice i k = take (k-i) . drop i

Exercise 2

rotate n l = drop n l ++ take n l

Exercise 3

everyOther [] = []
everyOther [x] = [x]
everyOther (x:y:xs) = x : everyOther xs

Exercise 4

countOccurences x [] = 0
countOccurences x (y:ys) =
  countOccurences x ys + (if x == y then 1 else 0)

Exercise 5

insertElem x 0 l = x : l
insertElem x k [] = []
insertElem x k (y:ys) = y : insertElem x (k-1) ys

Exercise 6

divides p q = p `mod` q == 0

Exercise 7

isPrime n
  | n > 1 = not $ any (divides n) [2..n-1]
  | otherwise = False

Exercise 8

twinPrime n = isPrime n && isPrime (n+2)