2014/07/22 Haskellその3 練習問題を解く2
StartHaskell2 wikiの問題を解いてみる
問1:偶数と奇数を分ける。
- 整数のリストを受け取り、奇数だけのリスト偶数だけのリストに分ける関数をつくろう
oddEven :: [Int] -> ([Int],[Int])
oddEven [] = ([],[])
oddEven (x:xs)
| odd x ==True = tupleC ([x],[]) $ oddEven xs
| otherwise = tupleC ([],[x]) $ oddEven xs
where
tupleC :: ([a],[b]) -> ([a],[b]) -> ([a],[b])
tupleC (x1,y1) (x2,y2) = (x1 ++ x2 ,y1 ++ y2)
問2:等比数列
- 等比数列を生成する関数を作ろう
gp :: (Num a) => a -> a -> [a]
gp n r = n : map (*r) (gp n r)
問3:フィボナッチ数列のn番目を返す関数を作ろう
- フィボナッチ数のn番目を返す関数を作る。
fib :: Integer -> Integer
fib 0 = 0
fib 1 = 1
fib n = fib(n-1) + fib (n-2)
高階関数
問4:部分適用された関数の型
- 関数の型を調べる。
※Ans : (答え)
Q1: max 5
max の定義は
max :: (Ord a) => a -> a -> a
max 5は (Ord a) => a -> aとなる。
そして、5はNum型のインスタンスとなるので、
型クラス制約にNumがつく。
つまり、
Ans1 : (Num a,Ord a) => a -> a
である。
Q2:takeWhile (<100)
takeWhileの定義は
takeWhile :: (a -> Bool) -> [a] -> [a]
述語を受け取り、Falseになるまでのリストを返す。
例: takeWhile(<100) [99,100,101,99]
結果: [99]
takeWhile (<100) は
(Num a) => [a] -> [a] となる。
(<100)でNum型のインスタンスと決定しているからである。
さらに、順序も比較できなければいけないのでOrd型のインスタンスでもある。
つまり
Ans2 : (Num a,Ord a) => [a] -> [a]
である。
TIPS:似ている関数にfilterがあるが、filterはTrueであるものを全て返す関数である。
上の例のtakeWhileをfilterにすると、
結果: [99,99] となる。
Q3 : zipWith (+)
zipWithの定義は
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWithは(a -> b -> c)の関数を受け取り、それを[a] と [b]に適用するものである。
例 : zipWith (+) [1,2,3] [1,2,3]
結果: [2,4,6]
zipWith (+) は
(+)の関数が Num a という型クラス制約を持っているので
zipWith の a と b は Num型のインスタンスとなる。
つまり、
zipWith :: (Num a) => (a -> a -> a) -> [a] -> [a] -> [a]
となる。
これを部分適用するので、zipWith (+) は
Ans 3: (Num a) => [a] -> [a] -> [a]
となる。
問5:コラッツ数列
- コラッツ数列を返す関数を実装しよう。
- 与えられた数nに、以下の操作を繰り返し適用して、数列を生成する。
- nが偶数なら、n/2 を返す
- nが奇数なら、2*n+1 を返す
- たとえば 13 から始めた場合、以下のような数列が得られる。
- 13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1
collatz :: Int -> [Int]
collatz 0 = error "Not a Natural Number"
collatz 1 = 1 : []
collatz n
| even n = n : collatz(n `div` 2)
| otherwise = n : collatz(n * 3 + 1)
問6:関数適用、関数合成
以下の関数の括弧を、関数適用($)で書き換えてみよう。
g :: [a] -> [a]
g xs = tail (tail (tail (tail xs)))
f :: [Int] -> [Int]
f xs = take 10 (map (*3) (filter even xs))
g' :: [a] -> [a]
g' xs = tail $ tail $ tail $ tail xs
f' :: [Int] -> [Int]
f' xs = take 10 $ map (*3) $ filter even xs