Real World Haskell 4.6 練習問題
練習問題を解いてみた。
import Data.Char (digitToInt) import Data.List -- 1. -- 負の場合と正の場合で分かれてるのが気になる。 asInt_fold :: String -> Int asInt_fold [] = 0 asInt_fold (x:xs) | x == '-' = - (foldl' atoi 0 xs) | otherwise = foldl' atoi 0 (x:xs) where atoi a b = (a * 10) + (digitToInt b) -- 2. asInt_fold2 :: String -> Int asInt_fold2 [] = 0 asInt_fold2 (x:xs) | x == '-' = - (foldl' atoi 0 xs) | otherwise = foldl' atoi 0 (x:xs) where atoi a b = if myIsDigit b then (a * 10) + (digitToInt b) else error("invalid parameter") myIsDigit a = a `elem` "0123456789abcdfeABCDEF" -- 3. -- Either の使い方でとまどった。なんだよ、Right, Left って。 -- 練習問題はここまでに出てきたもので実装するものだとばかり思い込んでいたけど... -- おかげで、myIsDigit なんて作っちゃったし。 type ErrorMessage = String asInt_either :: String -> Either ErrorMessage Int asInt_either [] = Right 0 asInt_either (x:xs) | x == '-' = let bad = (validate xs) in if null bad then Right (-(foldl' atoi 0 xs)) else Left (message bad) | otherwise = let bad = (validate (x:xs)) in if null bad then Right (foldl' atoi 0 (x:xs)) else Left (message bad) where validate xs = snd (span myIsDigit xs) myIsDigit a = a `elem` "0123456789abcdfeABCDEF" message a = "non-digit'" ++ (head a:'\'':[]) atoi a b = (a * 10) + (digitToInt b) -- 4. myConcat :: [[a]] -> [a] myConcat xs = foldr (++) [] xs -- 5. myTakeWhileR :: (a -> Bool) -> [a] -> [a] myTakeWhileR p (x:xs) | p x = x : myTakeWhileR p xs | otherwise = [] myTakeWhileR _ _ = [] myTakeWhileF :: (a -> Bool) -> [a] -> [a] myTakeWhileF p xs = foldr step [] xs where step a b | p a = a : b | otherwise = [] -- 6. -- 再帰で書いた方が簡単だった。 -- foldl' と foldr の違いを理解していなかったのが原因 myGroupBy :: (a -> a -> Bool) -> [a] -> [[a]] myGroupBy p [] = [] myGroupBy p (x:xs) = foldl' step [[x]] xs where step ys a | p (head (last ys)) a = init ys ++ [(last ys)++[a]] | otherwise = ys ++ [[a]] -- 7. -- 時間がなかったので、パッとできたものだけ。 -- cycle は畳み込みじゃ実装できなさそうだけど...。 -- リストの先頭からアクセスしなければいけない関数は foldl' を使った方がよさげ -- any なんかは、順番は関係ないのでどっちでもいいのか? myAny :: (a -> Bool) -> [a] -> Bool myAny f xs = foldr step False xs where step x bool | f x = True | otherwise = bool