駆け足で読む『プログラミングHaskell』9 対話プログラム(IOがしたい)

  • IO型の特殊性
    • IO型は対話形式にするための仕組み
      • HaskellはIOを除くと、「ファイルにすべてを書き込んで(→コンパイルして)→実行する」〜「いつも同じことをするだけ」という処理を作る
      • Haskellで対話式入出力をするときは、対話の受付口と対話の返却口を開いてやる
      • Haskellでは、対話は「受付口」と「返却口」のペアとして考えている
      • この対話の「受付口」と「返却口」とは、「引数」と「返り値」という関係ではない
      • したがって、「『受付口』と『返却口』とでできたその一塊」を一つの型としてとらえて、IO型と名付ける
    • IO型の使い方の特殊性
      • IO型はその他の普通の型と「並置して」扱う
      • IO型はその他の普通の型と「並置して」扱うとき、その動作を「アクション」と呼ぶ
    • -
  • IO型を持つアクション
    • 3つある
      • getChar
        • 以下に示すように、"IO Char"という型があるだけであって、変化を起こす"->"はない
Prelude> :info getChar
getChar :: IO Char 	-- Defined in System.IO
      • putChar
Prelude> :info putChar
putChar :: Char -> IO () 	-- Defined in System.IO
      • return
Prelude> :info return
class Monad m where
  ...
  return :: a -> m a
  ...
  	-- Defined in GHC.Base
Prelude> putChar 'a'
aPrelude> getChar
a
'a'
Prelude> Prelude
Prelude> let x = 3
Prelude> x
3
Prelude> return x
3
  • 基本アクションを順序づけて並べる
    • 次の処理は m がモナドクラスを表しているが
Prelude> :info >>=
class Monad m where
  (>>=) :: m a -> (a -> m b) -> m b
  ...
  	-- Defined in GHC.Base
infixl 1 >>=
    • IO型がモナドクラスなので、mをIOに書き換え、aをChar、bもCharとすれば
  (>>=) :: IO Char -> (Char -> IO Char) -> IO Char
    • となる
    • これは、getChar アクションの型があって、その次にreturnアクションの型があって、次にまたgetCharアクションの型がある、と読める
    • ここでIOしながらの作業であることを忘れないために、一連の流れの中でIOが消えることはない
  • do記法
    • アクションの順序付けの読みやすい記載の仕方
m a -> (a -> m b) -> m b
    • IO a をして、そのうち、プログラム本体で扱うことが許されたaのみを受けとって(a -> IO b) をして、という部分は、IOを渡さないことがわかっているので、以下のように、IOの関係ないものの受け渡しのように書いても、誤解がない
    • そのための記法であることの符丁として"do"が使われていて、do記法と呼ばれる
hoge do c <- getChar
     putChar c