{- Exercise 6.1 -}
sh :: [Integer] -> Integer
sh xs = undefined

removeAt :: Integer -> [a] -> [a]
removeAt n xs = undefined

insertS :: Ord a => a -> [a] -> [a]
insertS x ys = undefined


{- Exercise 6.2 -}
code :: Char -> String
code 'a' = "01"
code 'b' = "1"
code 'c' = "001"
code 'd' = "0001"

code2 :: Char -> String
code2 'a' = "11"
code2 'b' = "101"
code2 'c' = "01"
code2 'd' = "0011"

isPrefix, neitherPrefix :: String -> String -> Bool
isPrefix s t = null s || (not (null t) && head s == head t && isPrefix (tail s) (tail t))
neitherPrefix s t = not (isPrefix s t) && not (isPrefix t s)

{- TODO change this function and the type signature -}
encode :: String -> String
encode s = if null s then "" else code (head s) ++ encode (tail s)

{- TODO change this function and the type signature -}
decode :: String -> String
decode s = if null s then "" else [char]++ decode (drop (length (code char)) s) where
  char = aux 'a' 'd' s
  aux c d s = if (isPrefix (code c) s) then c else if (c == d) then
              error ("not decodable:"++s) else aux (succ c) d s

{- TODO write this function and the corresponding type signature -}
-- compareCodes ::
compareCodes = undefined

{- TODO find Strings (length at least 5) for which code and code2
   respectively generate shorter encodings, using compareCodes 
   add the strings as comments here
-}

{- TODO write this function and the corresponding type signature -}
-- nTimes ::
nTimes = undefined


{- Exercise 6.3 -}
{-
Add the type signatures here:
func_1 ::
func_2 ::
func_3 ::
-}

{- Tests -}
{- You don't have to understand the Haskell-code in the tests,
   but you can just invoke them after having implemented
   some exercises -}
testSh = sh [7,3,2,5,6] == 6 && sh [1,1,1] == 1 && sh [5,5,5,4] == 5

testRemoveAt = removeAt 3 ["Innsbruck", "Tirol", "Deutschland", "Wien"] == ["Innsbruck", "Tirol", "Wien"]
  && removeAt 66 [1,2,3] == [1,2,3]

testInsertS = insertS 3 [7,7,7,1,7] == [7,7,7,1,3,7]
  && insertS 3 [] == [3]
  && insertS "A" ["C","B","A"] == ["C","B","A","A"]
  && insertS 0 [123,123] == [123,123,0]

testEx1 = testSh && testRemoveAt && testInsertS

testNTimes = nTimes id 100 5 == 5 && nTimes (+1) 100 5 == 105

testEx2 = testNTimes && all ((\(x,_,_)->x) . compareCodes code code2) ["b", "ab", "bc"]

testAll = testEx1 && testEx2