練習問題

入門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",""]

……出直してきます。

「練習問題」への1件のフィードバック

  1. inits は次のように無限リストにも対応できますが
    take 10 $ map (take 1) $ inits [1..]
    myInits だと止まりません。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください