Haskell で手続き型もどきプログラミング

Haskell の do 記法のなかで、どの程度手続き型のプログラムができるかどうかを試してみたい。ファイルにプログラムを記述するのが面倒なので、Hugs のプロンプト上で一行プログラムで実行させた。

1) コンソールから文字列1行を読み込むプログラムの例。対話的プログラムを作るときの基本。

Hugs> do { putStr "Line: "; cs <- getLine; putStr cs }
Line: hello, world
hello, world

2) コンソールから読み込んだ文字列を整数型に変換して計算。数値の入力をするときに使う。

Hugs> do { cs <- getLine; print ((read cs :: Int) + 2) }
3
5

3) コンソールから数値を読み込んで変数 i (本当は変数ではない) に代入する。i <- return (....)と意味不明の return があるが、これは、<- が代入ではなくてIOモナドから値を取り出す演算子だから。関数 read の戻値は整数だから、これをIOモナドに変換してやらないと <- を使えないため。Haskell の手続き型のプログラムはあくまでも「もどき」なので注意が必要。

Hugs> do {cs <-getLine; i <- return(read cs :: Int); print i }
20
20

コンソールから整数を読み込む関数 getInt は型指定をすれば次の簡単なプログラムで実現できる。ただし、ファイルにプログラムを作成する必要がある。

getInt :: IO Int
getInt = readLn

4) 上のテクニックを使って1からコンソールから入力した n までの数の総和を計算してみた。ループの処理は無限リストから take で切り出すなどとしてインデックスのリストを作る方法が汎用的に使えそうだ。n = 3 から [1, 2, 3] を作るには take n [1..], m = 2, n = 10 から [2,3,..,10] を作るには、drop m (take (n+1) [0..]) とすればよい。

Hugs> do {cs <-getLine; i <- return(read cs :: Int); print (sum (take i [1..])) }
10
55

5) if ~ then ~ else ~ 構文を使った例。Haskell では else 以下を省略できない。

Hugs> do {c <- getLine; if c == "y" then print "yes" else print "no" }
y
"yes"

このように、手続き型プログラミングのようなプログラミングはHaskell でも記述できる。しかし、せっかく関数型のプログラム言語を使うのだから、極力関数は、do 記法の外側でプログラムして、手続き型プログラミングもどきの量は必要最小限に留めたほうがよい。
[PR]
by tnomura9 | 2010-10-12 12:48 | Haskell | Comments(0)
<< IOモナドの正体 Haskell の手続き言語もどき >>