bitterharvest’s diary

A Bitter Harvestは小説の題名。作者は豪州のPeter Yeldham。苦闘の末に勝ちえた偏見からの解放は命との引換になったという悲しい物語

Haskell ドリル16 パターン照合 (解答)

1.概略

前の記事再帰関数を求める問題を出したが、ここではその回答を示す。回答は一つだけでなく複数あるので、ここで示す回答はその一例だと思ってほしい。

なお、それぞれの関数には型シグネチャもつけた。

問題1:リストから先頭の要素を散り除く関数tail'を作成せよ。

tail' :: [a] -> [a]
tail' [] = error "No list."
tail' (_:xs) = tail1 xs
  where
    tail1 [] = []
    tail1 (y:ys) = y : tail1 ys

このプログラムでは、先頭の要素を取り除いた後、tail1を呼ぶが、その記述はwhereをつけてその後に記した。また、_のところは、変数、例えば、nが入るが、その変数名は使われることがないので、無名の変数にしてある。以下でも同じである。

問題2:リストから最後の要素を散り除く関数init'を作成せよ。

init' :: [a] -> [a]
init' [] = error "No List."
init' [_] = []
init' (x:xs) = x : init' xs

問題3:リストの長さを求める関数length'を作成せよ。

length' :: [a] -> Int
length' [] = 0
length' (_:xs) = 1 + length' xs

問題4:リストからn番目の要素を取り出す関数nthを作成せよ。

nth :: Int -> [a] -> a
nth _ [] = error "Short List"
nth 1 (x:_) = x
nth n (_:xs) = nth (n - 1) xs

リストの最初の要素を1番目と考えてプログラムを作成した。0番目と考える場合には修正する必要がある。

問題5:あるリストの最初からn番目までをそっくり取りだした部分リストを得る関数take'を作成せよ。

take' :: Int -> [a] -> [a]
take' _ [] = []
take' 1 (x:_) = [x]
take' n (x:xs) = x : take' (n - 1) xs

問題6:文字列からブランクを取り除く関数removeBlankを作成せよ。

removeBlank :: String -> String
removeBlank [] = []
removeBlank (x:xs)
  | x == ' ' = removeBlank xs
  | otherwise = x : removeBlank xs

上記のプログラムでStringは[Char}の言い換えである。

問題7:リストから要素xと要素yを取り除く関数remove'を作成せよ。

remove' :: (Eq a) => a -> a -> [a] -> [a]
remove' _ _ [] = []
remove' x y (z:zs)
  | x == z || y == z = remove' x y zs
  | otherwise = z : remove' x y zs

問題8:数列から偶数を取り除く関数removeEvenを作成せよ。

removeEven :: [Int] -> [Int]
removeEven [] = []
removeEven (x:xs)
  | mod x 2 == 0 = removeEven xs
  | otherwise = x : removeEven xs

問題9:リストを反転させる関数reverse'を作成せよ。

reverse' :: [a] -> [a]
reverse' [] = []
reverse' (x:xs) = reverse xs ++ [x]

問題10:リストが与えられた時、両端の要素を除いた部分リストを反転させる関数reverse1を作成せよ。

reverse1 :: [a] -> [a]
reverse1 [] = error "No List."
reverse1 [_] = error "Short List"
reverse1 (_:xs) = reverse1' xs
  where
    reverse1' [_] = []
    reverse1' (y:ys) = reverse1' ys ++ [y]