ちょっと練習問題を解く
入門Haskellを読みつつモナドの記述があまりに少ないので以下のサイトの「自分自身を出力するプログラム」に書いてあるmonadの数学的定義を読んでみるけど定義5までで死亡。ちゃんと理解するなら圏論の本買ってこないとだめぽ。
http://www.ipsj.or.jp/07editj/promenade/
とりあえず練習問題回答
問題1
linesCount str = outLines str where outLines [] = 0 outLines (c:cs) | c == '\n' = 1 + inLines cs | otherwise = outLines cs inLines [] = 0 inLines (c:cs) | c == '\n' = inLines cs | otherwise = outLines cs wordsCount str = outWords str where outWords [] = 0 outWords (c:cs) | isAlphaNum c = outWords cs | c == '`' = inQuote cs | otherwise = inWords cs inWords [] = 0 inWords (c:cs) | isAlphaNum c = 1 + outWords cs | c == '`' = inQuote cs | otherwise = inWords cs inQuote [] = 0 inQuote (c:cs) | c == '\'' = 1 + outWords cs | otherwise = inQuote cs
問題2
import Char import System.Environment wordsCount2 :: String -> IO () wordsCount2 str = putStrLn $ intToStr $ outWords str where wordScan [] f = 0 wordScan (c:cs) f | isAlphaNum c = f $ outWords cs | c == '`' = inQuote cs | otherwise = inWords cs outWords str = wordScan str id inWords str = wordScan str (1+) inQuote (c:cs) | c == '\'' = 1 + outWords cs | otherwise = inQuote cs intToStr :: Int -> String intToStr num = if (num < 10) then [intToDigit num] else (intToStr $ quot num 10) ++ [intToDigit $ rem num 10] main = getArgs >>= mapM_ wordsCount2
ちょっとmain書いてみたけどやっぱ嵌まった。
Int -> Stringの標準的な関数がわからなかったのでWebで探してきて拝借。
wordsCountはさっきまでのだとString -> Int型となってしまいmapM_の型
mapM_ :: (Monad m) => (a -> m b) -> [a] -> m ()
と一致しないためString -> IO ()型に改良。
そんで>>=だけど、右辺のmapM_ wordsCount2はwordsCount2にargsのひとつ(String)を渡してIO ()を返すのでIO ()型。getArgsは IO [String]なので結局mainは
IO [String] -> ((String -> IO ()) -> [String] -> IO ()) -> IO ()
となります。
しかし、極めて単純なmainすら簡単には書けないという噂は本当だった。