home


[入出力]

純粋関数型言語であるHaskellの入出力は,Cなどの手続き型の言語と比べちょっと変わった方法で実現されています.

1. 出力

まずは"Hello world!"を表示してみます.これにはputStrLn関数を使います. ghciなどのインタラクティブ環境で,putStrLn を用いた"Hello world!"の適用は以下のようになります.
Prelude> putStrLn "Hello world!"
Hello world!
これだけみるとCなどの手続き型言語とたいして変わらないように見えますが, "Hello world!"を端末(標準出力)に出力しているのは,putStrLn関数ではありません. Haskellは純粋関数型言語ですので,全ての関数は純粋でなければなりません. 関数が純粋であるとは,関数は引数によって決まる返り値を返すのみで,副作用をまったく持たないということです. もしこのputStrLn関数が何か返り値を返す以外に文字列を出力する操作を直接行ったとしたら,その時点で純粋では無くなってしまいます.
putStrLn関数は引数として与えられた文字列strを端末に出力するのではなく,"strを出力する"という指示を表した処理系依存のデータ構造を持った値を返します. そしてその値を受け取った処理系の方が,実際の入出力を行います. つまり,putStrLn関数は副作用が必要な仕事を自分で行う代わりに,処理系に押し付けています. "str1を出力したあとにstr2を出力する"ことを表す値は,"str1を出力する"ことを表す値と"str2を出力する"ことを表す値を演算子">>"でつなぐことで得られます.putStrはputStrLnとほぼ同様ですが,改行コードを付加しないのが違いです.
Prelude> putStr "Hello" >> putStrLn " world!"
Hello world!

2. 入力

端末から一行読み込むには無引数の関数getLineが使えます. getLineもputStrLnと同様に自分では入出力を行いません.代わりに"文字列を一行読み込む"という指示を表した値を返します. その値を受け取った処理系が,実際の入力操作を行います.
Prelude> getLine
This is a pen.
"This is a pen."
getLineを適用すると入力待になり,何か入力すると終了します.ここでは"This is a pen"と入力しています.(その後処理系がさらに入力された値を画面にエコーバックしています)

3. 入力と出力の合成

「文字列を一行読み込むことを表す値」と,「文字列を引数として受け取りその文字列を出力することを表す値を返す関数」を">>="演算子を用いてつなげて適用すると, 「文字列を一行読み込み,その文字列を出力することを表す値」を得ることが出来ます.
Prelude> getLine >>= putStrLn
hello
hello
もう少し複雑なことをする例として,「端末から一行読み込み,それが"Hi"だったら"Hello"を出力し,それ以外だったら"Pardon?"を出力することを表す値」は以下のようにして得ることが出来ます.(Hiは入力待ちになった後で,端末から入力しています)
Prelude> getLine >>= (\ str -> if str=="Hi" then putStrLn "Hello" else putStrLn "Pardon?")
Hi
Hello
上記は無名関数を用いていますが,以下のように定義しても同じです.
reply str = if str=="Hi" then putStrLn "Hello" else putStrLn "Pardon?"
call = getLine >>= reply
無引数の関数「call」の適用例は以下のようになります.
*Main> call
Hi
Hello