仕事が忙しくて書けてなかったけど、忘れたわけではない。
入出力の型
IO a
の簡易説明、っていうかこのWorld
を使った説明はごまかしだよなあ。
写経したコードを試しに実行する時に困るんだよねえ。
カリー化によって(最近、ScalaやGroovy界隈で話題だったね)、引数をとるIO型を定義しなくても、a -> IO b
で充分というのは納得。
基本アクション
getChar
とputChar
を例にとったreturn
の説明。
第8章でもreturn
は出てきたけど、そこではオレオレreturnだったし、副作用の話はしていなかった。
モナドについては教科書以外で自習しておいたから、この節は適当に読み飛ばす。
順序付け
演算子 >>=
とdo
記法の説明。
第8章でも出てきたけど、そこではオレオレbindだったので実際にはdo記法でプログラムを書くことはできなかった。
この節も適当に読み飛ばしつつ、やっとdo記法が使えるので、あらためて書き方をおさらいしておく。
アクションの部品
さて、写経の時間。
今回はgetLine
、putStr
、putStrLn
を最初に定義しているけど、この3つの関数は標準ライブラリに入っているからそれを使うことにする。
strlen :: IO () strlen = do putStr "Enter a string: " xs <- getLine putStr "The string has " putStr (show (length xs)) putStrLn " characters"
さて、次が問題で。
beep :: IO () beep = putStr "\BEL" cls :: IO () cls = putStr "\ESC[2J" type Pos = (Int, Int) goto :: Pos -> IO () goto (x, y) = putStr ("\ESC[" ++ show y ++ ";" ++ show x ++ "H") writeat :: Pos -> String -> IO () writeat p xs = do goto p putStr xs seqn :: [IO a] -> IO () seqn [] = return () seqn (a: as) = do a seqn as
これを試すんだけど、WinHugsではエスケープシーケンスが効かない。というか、コマンドプロンプトで実行するhugs.exeでも効かない。
最近のWindowsでエスケープシーケンスを効かせたいときは、Cygwinを使うか、telnet経由で実行するという方法が考えられる。
とりあえず前者は嫌いなので却下して、後者をやってはみたが、面倒だな……。エスケープシーケンスが必須な練習問題でもない限りは無視しようと思う。
電卓
expr :: Parser Int
が存在していることが前提と書いてあるので、第8章の練習問題で書いたexpr
を持ってくる。減算演算子が右結合のやつだけど、別にいいよね。
ついでに、do
記法で書きなおしておく。
factor :: Parser Int factor = do symbol "(" e <- expr symbol ")" return e +++ natural term :: Parser Int term = do f <- factor (do symbol "*" t <- term return (f * t) +++ do symbol "/" t <- term return (f `div` t) +++ return f) expr :: Parser Int expr = do t <- term (do symbol "+" e <- expr return (t + e) +++ do symbol "-" e <- expr return (t - e) +++ return t)