普通の関数をIOモナドに変える

IOモナドが嫌われる理由の一つは、IOモナドの外で定義した普通の関数がIOモナドの中では使えないことだろう。これも、IOモナド型関数とは「引数を一つだけとり、IO型の戻り値を返す。」という観点から考えると、簡単に解決することができる。つまり、引数が一つだけの関数があれば、その関数を return 関数と合成してやればそれはそのまま、IOモナド型関数になってしまうということだ。

例えば、("hello, " ++) という関数は、String 型の変数をひとつとり、文字列 "hello, " と連結した文字列を返す関数だが、

Hugs> ("hello, " ++) "Dolly"
"hello, Dolly"

これを、return 関数と合成した return . ("hello, " ++) はIOモナドになってしまう。したがって、標準のIOモナド型関数と >>= 演算子で連結することができる。

Hugs> getLine >>= return . ("hello, " ++) >>= putStrLn
Dolly
hello, Dolly
普通の関数をIOモナド型関数にしてしまえば、どんなものも >>= 演算子でつなげてしまうことができるので、プログラム作成がちょうど Unix のパイプライン処理のようにモジュールをつなげる操作になってしまう。

Hugs> :l List
List> getLine >>= return . (read :: String -> [Int]) >>= return . sort >>= print
[2,3,5,1,6]
[1,2,3,5,6]

上のプログラムは、次のように手続き型のプログラムに似せて作ることができるが、簡単な例なら do 記法よりは >>= 演算子でつないでやった方が楽だ。 do 記法の時は、return 関数との合成は $ 演算子で行う。(上の例では関数の後ろに引数がないから . で合成できる。)

import List

main = do
   cs <- getLine
   lst <- return $ (read :: String -> [Int]) cs
   print (sort lst)

このように、IOモナドを「一つの引数をとり、IO型の戻り値を返す関数」ととらえただけで、簡単に既存の関数もIOモナド型関数化して利用できるようになる。
[PR]
by tnomura9 | 2010-10-19 08:25 | Haskell | Comments(0)
<< Windows に Haske... メタ思考 >>