Daniel Keast

Real World Haskell 4

haskell, programming

These are the first exercises of chapter 4.

Write your own “safe” definitions of the standard partial list functions, but make sure they never fail.

safeHead :: [a] -> Maybe a
safeHead []     = Nothing
safeHead (x:xs) = Just x

safeTail :: [a] -> Maybe [a]
safeTail []     = Nothing
safeTail (x:xs) = Just xs

safeLast :: [a] -> Maybe a
safeLast []     = Nothing
safeLast (x:[]) = Just x
safeLast (x:xs) = safeLast xs

safeInit :: [a] -> Maybe [a]
safeInit []     = Nothing
safeInit (_:[]) = Just []
safeInit (x:xs) = Just (x : inner xs)
    where inner []     = []
          inner (_:[]) = []
          inner (a:as) = a : inner as

Write a function splitWith that acts similarly to words but takes a predicate and a list of any type, and then splits its input list on every element for which the predicate returns False:

splitWith :: (a -> Bool) -> [a] -> [[a]]
splitWith p xs = split [[head xs]] (tail xs)
    where split (x:xs) (y:ys) = if p y
          then split (x:xs ++ [[y]]) ys
          else case safeInit xs of
              Just i  -> split (x:i ++ [last xs ++ [y]]) ys
              Nothing -> split [x ++ [y]] ys
          split xs [] = xs

Using the command framework from the earlier section ‘A Simple Command-Line Framework’, write a program that prints the first word of each line of its input.

import System.Environment (getArgs)

interactWith function inputFile outputFile = do
  input <- readFile inputFile
  writeFile outputFile (function input)

main = mainWith myFunction
  where mainWith function = do
          args <- getArgs
          case args of
            [input,output] -> interactWith function input output
            _ -> putStrLn "error: exactly two arguments needed"

        -- replace "id" with the name of our function below
        myFunction = firstWord

firstWord :: String -> String
firstWord s = unlines (firstWord (lines s))
            where firstWord [] = []
                  firstWord (l:ls) = (head (words l)) : firstWord ls

Write a program that transposes the text in a file. For instance, it should convert “hello\nworld\n” to “hw\neo\nlr\nll\nod\n”.

rotated :: String -> String
rotated s = unlines (rotate (lines s))
          where rotate [] = []
                rotate xs = [heads xs] ++ rotate (rest xs)

                heads []     = []
                heads (x:xs) = head x : heads xs

                rest []     = []
                rest (x:xs) = if null (tail x)
                              then []
                              else [tail x] ++ rest xs