練習問題
「入門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",""]
……出直してきます。
