入出力と do 記法

プログラムと言うからには入力と出力を扱えなきゃいけない。でないと何の役にも立たないからな。
ただ,純粋関数型言語Haskell にとってはこの入出力というのは特殊なもののようだ。

  • 入出力は手続き的にならざるを得ない。なぜなら出力が入力よりも先に行えるはずがないから。だから,いつ,どんな順で評価しても結果が変わらない他の関数とはちがう。
  • 副作用がある。入出力をする関数を評価すると,評価の結果として値が返ってくるのとはべつに,入力を受け取ったり,画面に何かを出力したりということが起こる。これを副作用という。
  • 評価するたびに結果が異なる。たとえば Ruby では gets で標準入力から値を得ることができるけど実行するたびに違う値が返ってくる。Haskell ではこれはまずい。

Haskell ではこのような問題を避けるために特別な仕組みがある。それが do 記法。
口(?)で説明するのは難しいので例を示す。このプログラムはコマンドラインから受け取ったパラメータを標準出力に出力する。ようするに echo だ。

 import System
 
 main = do args <- getArgs
           putStr $ unlines args

この do記法の中には2つの動作 (action) がある。 args <- getArgs でコマンドラインパラメータを受け取ってargsに代入する(空白で区切られて文字列のリストになる)。そして putStr $ unlines args で標準出力へ1行にひとつずつ出力する。do記法の中の action は順番に実行される。
この様に do 記法の中ではプログラムの他の部分と違って手続き的に書くことができる。というか,(Haskellにとって)異質なものを他の部分から分離している,という方がいいだろうか。


もう少し詳しく言うと,do記法はべつに入出力のためだけのものではなくて,モナドという仕組みなんだけど,このモナド,なんだかよくわからないのでここでは脇に置いておく。とにかく,標準入出力やファイルを使おうとしたら do 記法を使えばいいってことだ。

上のプログラムをコンパイルして実行するとこうなる。あ,import System は getArgs を使うのに必要。

 >type hecho.hs
 import System
 
 main = do args <- getArgs
           putStr $ unlines args
 
 >ghc -o hecho hecho.hs
 
 >hecho abc def ghi
 abc
 def
 ghi
 

OK。これでプログラムが書けるぞ。