IOモナドでパイプラインプログラム

IOモナドでパイプライン処理のプログラムを作ってみた。

パイプライン処理とはUnixのフィルタープログラムで使われている方法で、プログラムの出力を次のプログラムの入力につなげて処理をしていくやり方だ。IOモナドを使ったプログラムでも同様の方法を使うことができる。というより、do 記法の中の一見手続き型のプログラムも、実は、IOモナドの関数を>>=演算子によるパイプライン処理で繋いだものだ。

したがって、IOモナドでプログラミングするときパイプライン処理を意識してプログラムすれば楽なのだ。Hugsを使ってワンライナーでパイプライン処理のIOモナドプログラミングをしてみた。

まずはじめに、コンソールから文字列を入力してそれを出力するプログラムを書いてみた。

Hugs> getLine >>= putStrLn
hello
hello

パイプラインの中を流れるデータはプログラムのコードからは明示的には見えないが、getLine でコンソールから入力された文字列が >>= 演算子を介して putStrLn に渡され、それがモニタに表示されたと考えると分かりやすい。

つぎは、入力した文字列を加工してみる。

Hugs> getLine >>= hello >>= putStrLn where hello cs = return ("hello, "++cs)
world
hello, world

これは、getLine で入力した文字列に"hello, "を付け加えて putStrLn に渡している。上の hello という関数が自前のIOモナドで、where 以下に定義してある。例によって引数をひとつとりIO型のデータを return 関数で返している。

次のプログラムではコンソールから整数のリストを読み込み、その和を計算している。

Hugs> getLine >>= lread >>= return . sum >>= print where lread ls = return (read ls :: [Int])
[1,2,3,4,5]
15

getLine でリストの文字列を読み込み、lread 関数で [Int] 型のデータに変換し、sum 関数でその和を取り、print 関数で画面に出力している。return . sum のように、Haskellの世界の関数を return 関数を使ってIOモナドの世界に移していることを注目して欲しい。

つぎは、コンソールから文字列のリストを入力し、それをソートする。

Hugs> :l List
List> getLine >>= lread >>= return . sort >>= print where lread ls = return (read ls :: [String])
["hello","world","how","are","you"]
["are","hello","how","world","you"]

このように、IOモナドのKleisli圏の関数を >>= 演算子で合成していくことによってIOモナドのプログラミングを行っていくのを意識すると、IOモナドのプログラミングが楽しくなる。

Haskellは純粋関数型のプログラム言語で、IO関係の処理もやはり関数で記述される。手続き型のプログラムの発想を一旦捨てて、関数型の発想では同じようなことがどのようにできるのか考えると、IOモナドのプログラミングに対する不満も解消されるのではないだろうか。

要は慣れの問題で、いろいろなプログラムを関数型プログラムの発想から作っているうちに、IO関係の処理も自然に関数型のプログラムで記述できるようになるだろう。
[PR]
by tnomura9 | 2010-10-29 07:50 | Haskell | Comments(0)
<< IOモナドの >>... モナドのKleisli圏 >>