第9章 対話プログラム #1

仕事が忙しくて書けてなかったけど、忘れたわけではない。

入出力の型

IO aの簡易説明、っていうかこのWorldを使った説明はごまかしだよなあ。 写経したコードを試しに実行する時に困るんだよねえ。

カリー化によって(最近、ScalaやGroovy界隈で話題だったね)、引数をとるIO型を定義しなくても、a -> IO bで充分というのは納得。

基本アクション

getCharputCharを例にとったreturnの説明。 第8章でもreturnは出てきたけど、そこではオレオレreturnだったし、副作用の話はしていなかった。

モナドについては教科書以外で自習しておいたから、この節は適当に読み飛ばす。

順序付け

演算子 >>= do記法の説明。 第8章でも出てきたけど、そこではオレオレbindだったので実際にはdo記法でプログラムを書くことはできなかった。

この節も適当に読み飛ばしつつ、やっとdo記法が使えるので、あらためて書き方をおさらいしておく。

アクションの部品

さて、写経の時間。 今回はgetLineputStrputStrLnを最初に定義しているけど、この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)