Real World Haskell 4.5 練習問題

久しぶりに Haskell。Real World Haskell の本を買ったはいいがなかなか進まない。まだ 4章。

問1

Maybe型で返すのはいいけど、返されたMaybe型の値をどう扱えばいいかまだわかっていない。

safeHead xs = if null xs then Nothing else Just (head xs)
safeTail xs = if null xs then Nothing else Just (tail xs)
safeLast xs = if null xs then Nothing else Just (last xs)
safeInit xs = if null xs then Nothing else Just (init xs)
問2

ネストが深い?

splitWith f xs =
  let (pre, suf) = break f xs
  in  if null pre
      then splitWith f (tail suf)  
      else pre : if   null suf
                 then []
                 else splitWith f (tail suf)


2010/07/29 修正

splitWith f xs =
  let (pre, suf) = span f xs
  in  if null pre
      then tailSplitWith f suf
      else pre : tailSplitWith f suf
  where tailSplitWith f (x:xs) = splitWith f xs
        tailSplitWith f []     = []
問3

ファイルの入出力部分は省略。次の問4も同様。map を使えばもう少し単純に書けるはず。でも、ここまででの内容で map はなかったような。なので、あえて使わずに解いてみた。

myFunction = initials

initials :: String -> String
initials input = unlines (headStrs (lines input))
  where headStrs (x:xs) = headStr x : headStrs xs
        headStrs _      = []
        headStr  (x:xs) = [x]
        headStr  _      = []
問4

問 1 で作った safeHead, safeTail を使おうと思ったが、前述の通り Maybe 型の扱い方がわからないので myHead, myTail を作った。
リストが空かの判定をパターンマッチを使っている関数と if 式を使っている関数がある。まとめた方がよかったかな。

myFunction = rotateLines

myHead :: String -> Char
myHead xs = if null xs then ' ' else head xs

myTail :: String -> String
myTail xs = if null xs then []  else tail xs

heads :: [String] -> String
heads (x:xs) = myHead x : heads xs
heads _      = []

tails :: [String] -> [String]
tails (x:xs) = myTail x : tails xs
tails _      = []

rotate :: [String] -> [String]
rotate xs =
  if null (concat xs) -- これが終了判定
  then []
  else heads xs : rotate (tails xs)

rotateLines :: String -> String
rotateLines xs = unlines (rotate (lines xs))

関数が多くなってくると次に作る関数名をどうしようか悩む。もう少しボキャブラリーが多ければな〜。