今日は目先を変えて練習問題をやろう。
「入門Haskell―はじめて学ぶ関数型言語」 p.72 より。
①前ページの実装から,takeとdropに大きな値や負の値が入った場合の対処をしなさい。
前ページの実装とはこれ。Prelude の関数とかぶってはいけないので名前は変えてある。
mytake 0 _ = [] mytake n (x:xs) = x : mytake (n-1) xs mydrop 0 xs = xs mydrop n (x:xs) = mydrop (n-1) xs
mytake に大きな値を入れるとリストそのもの,負の値を入れると空リストが返るようにする。逆に mydrop に大きな値を入れると空リスト,負の値を入れるとリストそのものが返るようにする。
mytake _ [] = [] mytake 0 _ = [] mytake n (x:xs) | n < 0 = [] | otherwise = x : mytake (n-1) xs mydrop _ [] = [] mydrop 0 xs = xs mydrop n (x:xs) | n < 0 = x:xs | otherwise = mydrop (n-1) xs
もっとすっきり書けそうだけどまぁいいか。実行結果。
*Main> mytake 10 [0,1,2,3,4,5] [0,1,2,3,4,5] *Main> mytake (-2) [0,1,2,3,4,5] [] *Main> mydrop 10 [0,1,2,3,4,5] [] *Main> mydrop (-2) [0,1,2,3,4,5] [0,1,2,3,4,5]
ふたつめ。
②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 のほうから(名前は変えてある)。
mysplitAt _ [] = ([], []) mysplitAt n xs = ((take n xs), (drop n xs))
結果。
*Main> mysplitAt 2 [1,2,3,4] ([1,2],[3,4])
よし。じゃ,これを使って mytake と mydrop を定義し直すと
mytake n xs = fst $ mysplitAt n xs mydrop n xs = snd $ mysplitAt n xs
結果は
*Main> mytake 3 [1,2,3,4,5] [1,2,3] *Main> mydrop 3 [1,2,3,4,5] [4,5]
もうひとつ。
③takeWhile は,(a -> Bool) -> [a] -> [a] という型です。takeと似ていますが,決まった数だけとるのではなく,要素を計算し たら真である限りtakeし,一度でも失敗したら残りは返しません。これを定義しなさい。
こんなんでどうかな。
mytakeWhile _ [] = [] mytakeWhile f (x:xs) | f x = x : mytakeWhile f xs | otherwise = []
*Main> mytakeWhile (\x -> x > 0) [3,2,1,0,-1,-2,-3] [3,2,1] *Main> mytakeWhile (\x -> x < 0) [3,2,1,0,-1,-2,-3] []