Haskellお勉強会第7日目まとめ


"Real World Haskell"の第4章の6節まで読み終えました。

Real World Haskell―実戦で学ぶ関数型言語プログラミング

Real World Haskell―実戦で学ぶ関数型言語プログラミング


Real World Haskell 第4章の読書メモ

  • 変数名にシングルクォートも使えるよ。あんまり付けると読みにくいけどね!
  • 末尾再帰は最適化されて定数量空間で実行されるよ
  • map はリストを受け取って同じ長さのリストを返す写像だよ!
  • 関数を引数に取るからmapは高階関数だ!
  • リストの畳み込みは「リストに対して何かの処理を行い、結果を順次纏めていき、最終的に結果を返す」ことだ!
  • haskellでは先頭からの畳み込みはfoldl関数、末尾からの畳み込みはfoldr関数だ!
  • 畳み込みは慣れないうちは読みにくいけどな、じきに慣れるからな!
  • foldrはリストの変換という意味でもよく使われるぞ!
  • foldlはサンクを多用するから結果として高くつくぞ
  • foldl'という関数はサンクを作らないfoldl関数だ

ここが気になる

  • filterとかがfoldrで書けるというのが、頭では理解できてもしっくりこないわ。リストの末尾に効率的に追加できる操作があればfoldlでもいけるんだろうけど。
  • 「前に前に追加」していくから末尾から走査しないと順序が合わないって考えればいいかな
  • foldrは無限リストに対してはめっぽう弱いのではあるまいか?

練習問題

  • 1 畳み込みを使ってasInt関数を定義しなさい
asInt_fold :: String -> Int
asInt_fold xs 
  | (head xs == '-') = (-1) * foldl step 0 (tail xs)
  | otherwise= foldl step 0 xs
  where step x y = x * 10 + digitToInt y
  • 2 上の関数を拡張してerrorを呼ぶようにしなさい
asInt_fold2 :: String -> Int
asInt_fold2 xs 
  | (head xs) == '-' =  (-1) * foldl step 0 (tail xs)
  | otherwise= foldl step 0 xs
  where step x y 
          | isDigit y = x * 10 + digitToInt y
          | otherwise = error "error"

オーバーフローの検出は、知らん!

  • 3 上の関数をEither使ってエラー処理しなさい

Eitherむつかしす。パス

  • 4 concatをfoldrで定義しなさい
myconcat :: [[a]] ->[a]
myconcat xs = foldr (++) [] xs
  • 5 takeWhileを明示再帰とfoldrで書きなさい
myTakeWhile :: (a -> Bool) -> [a] -> [a]
myTakeWhile pred (x:xs)
  | pred x = x : (myTakeWhile pred xs)
  | otherwise = []
myTakeWhile _ _ = [] 
myTakeWhile2 :: (a -> Bool) -> [a] -> [a]
myTakeWhile2 pred xs = foldr step [] xs
  where step y acc | pred y = y : acc
                   | otherwise = []
  • 6 groupByを独自実装しなさい
myGroupBy :: (a -> a -> Bool) -> [a] -> [[a]]
myGroupBy pred xs = foldl step [] xs
  where step acc y | null acc = [[y]]
                   | pred y (head(last acc)) = (init acc) ++ [((last acc) ++ [y])]
                   | otherwise = acc ++ [[y]]