IOモナドの多重ループ処理

IOモナドの多重ループ処理もそれほど特別の工夫もいらずに作れた。

for i n = if i <= n
  then do {for2 1 i; putStrLn ""; for (i+1) n}
  else return ()

  where
    for2 i n = if i <= n
      then do {putStr "*"; for2 (i+1) n}
      else return ()

実行例
Main> for 1 5
*
**
***
****
*****

内部ループの動作をする関数 for2 を定義すればよいだけだった。ただし、for2 も必ずIO型のデータを戻り値として返さなければならない。IO型の戻り値を返すようにするというのが、IOモナドのプログラムを行うときの大原則だ。

要するに、ループ処理がある時は、そのループを一つの再帰関数として記述し、その中でループが発生する多重ルーブの場合は、内部のループをまた別の関数として記述すれば良い。その際にその関数がIO型データを戻り値に返すようにして、IOモナド型の関数にしておくことが大切だ。一つのループに一つの末尾再帰関数とイメージすると分かりやすい。

しかし、これも次のプログラムを思いつくほうが速かった。

Main> mapM putStrLn $ map (flip(replicate) '*') [1..5]
*
**
***
****
*****

IOモナドのプログラムに苦しんでいるのは、手続き型プログラムのノウハウをそのまま持ち込もうとするからなのではないだろうか。たくさんのスニペットをまねして動作させているうちに、IOモナドのプログラムの癖のようなものが身についてきたら、悩まなくなるのではないだろうかという気がした。結局のところ慣れの問題なのだろう。

IOモナドの謎も一応自分的には解けたような気がするので、Haskell 関連の記事は今回でお休みにしたい。(「今日のHaskell」 は続けられるだけ続けてみたい。)


今日のHaskell
Main> (-) 2 1
1
Main> flip (-) 2 1
-1

flip は関数の引数の順序を変える高階関数。map 関数の引数の関数と組み合わせて使うことが多い。
[PR]
by tnomura9 | 2010-11-07 00:14 | Haskell | Comments(0)
<< シミュレーション IOモナドのループ処理 >>