「入門Haskell―はじめて学ぶ関数型言語」 p.78 より。
(1) filter,inits,tails,zip,zipWith を定義しなさい。
myFilter f [] = [] myFilter f (x:xs) | f x = x:myFilter f xs | otherwise = myFilter f xs myInits [] = [] myInits xs = map ((flip take) xs) [1..(length xs)] myTails [] = [] myTails xs = map ((flip drop) xs) [0..(length xs -1)] myZip _ [] = [] myZip [] _ = [] myZip (x:xs) (y:ys) = (x,y) : myZip xs ys myZipWith f _ [] = [] myZipWith f [] _ = [] myZipWith f (x:xs) (y:ys) = f x y : myZipWith f xs ys
結果。
*Main> myFilter (> 0) [-2,-1,0,1,2] [1,2] *Main> myInits "abcde" ["a","ab","abc","abcd","abcde"] *Main> myInits "" [] *Main> myTails "abcde" ["abcde","bcde","cde","de","e"] *Main> myTails "" [] *Main> myZip [1,2,3] [1,2,3,4] [(1,1),(2,2),(3,3)] *Main> myZipWith (+) [1,2,3] [1,2,3,4] [2,4,6]
myZip,myZipWith の余った要素が無視されるのは正しい動作。
(2) sum,product,and,or のそれぞれを fold 系を使って定義しなさい。
mySum :: (Num a) => [a] -> a mySum = foldl (+) 0 myProduct :: (Num a) => [a] -> a myProduct = foldl (*) 1 myAnd :: [Bool] -> Bool myAnd = foldl (&&) True myOr :: [Bool] -> Bool myOr = foldl (||) False
結果。
*Main> mySum [1,2,3,4,5] 15 *Main> myProduct [1,2,3,4,5] 120 *Main> mySum [] 0*Main> myProduct [] 1 *Main> myAnd [True, False, True] False *Main> myAnd [True, True, True] True *Main> myOr [False, False, True] True *Main> myOr [False, False, False] False
sum と product はそれぞれ 0,1 になる。
*Main> sum [] 0*Main> product [] 1
追記:
IO () さんから myInits が無限リストに対応できていないと指摘をもらった。コメント欄参照。
ああっ,本当だ。
*Main> take 10 $ map (take 1) $ myInits [1..] GHC's heap exhausted: current limit is 268435456 bytes; Use the `-M<size>' option to increase the total heap size.
ついでに気が付いたけど,inits の結果は先頭に空リストがあるじゃないか。この点でも違っている(これは「入門Haskell」も間違っている。p.75)。
Prelude List> inits "abcde" ["","a","ab","abc","abcd","abcde"]
えーと,もしかして tails も?
Prelude List> tails "abcde" ["abcde","bcde","cde","de","e",""]
……出直してきます。
inits は次のように無限リストにも対応できますが
take 10 $ map (take 1) $ inits [1..]
myInits だと止まりません。