『入門Haskell』練習問題例解(5)
takeとdrop
ではp.72の(1)から。
前ページの実装から、takeとdropに大きな値や負の値が入った場合の対処を行いなさい。
これは仕様通りに
myTake :: Int -> [a] -> [a] myTake _ [] = [] myTake n _ | n <= 0 = [] myTake n (x:xs) = x : myTake (n-1) xs myDrop :: Int -> [a] -> [a] myDrop _ [] = [] myDrop n xs | n <= 0 = xs myDrop n (_:xs) = myDrop (n-1) xs
でいいでしょう。
splitAt
p.72の(2)。
takeとdropを同時に実行する splitAt :: Int -> [a] -> ([a], [a]) があります。たとえば
splitAt 2 [1, 2, 3, 4] -- ([1, 2], [3, 4])のように、結果のタプルの第1要素がtake、第2要素がdropになります。このsplitAtを定義しなさい。また、takeとdropをsplitAtを使って定義しなおしなさい。
本来splitAtはtakeとdropを用いて
splitAt :: Int -> [a] -> ([a],[a])
splitAt n xs = (take n xs, drop n xs)
と定義されるのですが、ここでは逆にsplitAtからtakeとdropを定義しなさい、と言っています。
mySplitAt :: Int -> [a] -> ([a], [a]) mySplitAt n xs = mySplitTuple n ([], xs) where mySplitTuple _ (x, []) = (x, []) mySplitTuple n t | n <= 0 = t mySplitTuple n (x, y:ys) = mySplitTuple (n-1) (x ++ [y], ys) myTake :: Int -> [a] -> [a] myTake n xs = fst (mySplitAt n xs) myDrop :: Int -> [a] -> [a] myDrop n xs = snd (mySplitAt n xs)
こうなると思います。ここで使った mySplitTuple n (xs, ys) は「ysの頭からn要素取り除いてxsの尾に連結する」という関数です。
takeWhile
p.72の(3)です。
takeWhileは、(a -> Bool) -> [a] -> [a] という型です。takeと似ていますが、決まった数だけ取るのではなく、要素を計算したら真である限り take し、一度でも失敗したら残りは返しません。これを定義しなさい。
(2)よりは簡単ですね。
myTakeWhile :: (a -> Bool) -> [a] -> [a] myTakeWhile f [] = [] myTakeWhile f (x:xs) | f x = x : myTakeWhile f xs | otherwise = []
仕様書にも同じように書いてあります。