コンソールから入力した文字列を連結するには

Haskell でコンソールから入力した行を連結するにはどうしたらいいか考えた。IO モナドでループを記述するときのいい練習問題になる。最初は、再帰的定義や foldM を使ったらどうかと考えたがうまくいかなかった。

そこで、mapM がリストを返すことを思い出して、いったん getLine で取得した文字列をリストにしてそれを連結したらどうかと考えた。そこで、次のようにしてみたらエラーになった。

Prelude> mapM getLine [1..3]

:1:5:
Couldn't match expected type `a -> m b'
against inferred type `IO String'
In the first argument of `mapM', namely `getLine'
In the expression: mapM getLine [1 .. 3]
In the definition of `it': it = mapM getLine [1 .. 3]

getLine が引数をとらないのがいけないのだなと気づいたので、ダミーの変数を加えて、次のようにしたらうまくいった。

Prelude> mapM (\_ -> getLine) [1..3]
one
two
three
["one","two","three"]

そこで、この3行をつなげて表示できた。

Prelude> mapM (\_ -> getLine) [1..3] >>= putStrLn . unwords
one
two
three
one two three

おまけで、プロンプトもつけてみた。

Prelude> mapM (\_ -> putStr "input number> " >> getLine) [1..3]
input number> 1
input number> 2
input number> 3
["1","2","3"]

Haskell の IO モナドでループを書く場合は、手続き型言語のループと同じものを作ろうと思ってもうまくいかない。ループと同じような動作を、まったく別のやり方で関数型プログラム言語で作るにはどうするかと考えたほうがいいようだ。関数型のループの雛形の情報がもっとたやすく得られれば、IO モナドのループも怖くなくなるのだろう。
[PR]
by tnomura9 | 2011-10-23 10:45 | Haskell | Comments(0)
<< 空行で無限ループを脱出するには 女性ボーカリスト >>