IOモナドのループ処理

IOモナドのプログラミングは、基本的にIOモナドの関数を>>=演算子でつないでいくだけだということが分かった。

しかし、そうなると困ったことになる。ループ処理が記述できないのだ。関数を>>=演算子でつないでいく方法だと、処理は一方向にしか流れていかない。しかし、ループ処理の記述できないIO処理は役に立たない。いろいろとネット上をさまよったが、ループ処理を端的に解説してくれる記事が見つからなかった。

ただし、「Haskell ではループは全て再帰関数で記述する。」というコメントがあったので、無限再起する関数を書けばいいのではないかと思った。そこで、Hugsで次のように入力してみたが、show関数がないというエラーが出て動かなかった。

Main> loop where loop = do {getLine>>=putStrLn; loop}
ERROR - Cannot find "show" function for:
*** Expression : let {loop ($0 (0 do {...}) $0) $0 $0} in loop
*** Of type : IO a

いろいろ悩んだが、loop 関数もIOモナドの関数にするためには、IO型の戻り値を返さなければならないのだから、コードの最後に return () を入れて、IO () 型の戻り値を返すようにしてみたら、これがうまくいった。

Main> loop where loop = do {getLine>>=putStrLn; loop; return ()}
hello
hello
world
world
^C{Interrupted!}

これで無限ループができたので、回数限定のループを作ってみたが動いた。

Main> loop 2 where loop x = do {getLine>>=putStrLn; if x > 0 then loop (x-1) else return ()}
one
one
two
two
three
three

次に、入力が””ならループを脱出するようにしてみた。

Main> loop where loop = do {cs <- getLine; putStrLn cs; if cs == "" then return () else loop; return ()}
hello
hello
world
world

やはり、IOモナドのプログラミングには、手続き型の考え方を持ち込んではいけないようだ。ループ処理させることはできるが、それは、無限の再帰を行う関数を記述することでおこなう。>>=演算子を挟んだ処理は絶対に後戻りできないことを心に止めておかねばならない。

IOモナドのプログラミングは、一見手続き型言語風に見えても、あくまでも関数言語のプログラミングだ。手続き型言語の発想をそのままIOモナドのプログラミングに持ち込もうとしたために、IOモナドのプログラミングが必要以上に難しく写ってしまった。

Haskell を扱う上で大切なのは、全てを関数で考えるという発想の転換なのだ。
[PR]
by tnomura9 | 2010-10-31 08:44 | Haskell | Comments(0)
<< 再帰関数によるループを Ruby で IOモナドの >>... >>