ウォンツテック

そでやまのーと

ちょっと練習問題を解く

入門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すら簡単には書けないという噂は本当だった。