Haskell 入門


Haskell のファイルの読み出し書き込み

Haskell のファイルの読み出しは普通のプログラムだ。ファイル名を取得し、ファイル名からファイルハンドルを取得し、ファイルハンドルから内容を読みだす。Haskell といえども入出力は普通の手続き型のプログラムと一緒だ。ただし、do 関数の後にアクションを並べるところが違うくらい。

単純な読み書き

単純なファイルの読み書きなら、Haskell はワンライナーでできる。書き込みは writeFile、読み出しは readFile、追加書き込みは appendFile でできる。

Hugs> writeFile "hello.txt" "hello"

Hugs> readFile "hello.txt" >>= putStr
hello
Hugs> appendFile "hello.txt" ", world"

Hugs> readFile "hello.txt" >>= putStr
hello, world

代数的データの読み書き

文字列ではなく、リストなどのデータを記録するときは show 関数で、データを文字列に変換しておくと良い。

Hugs> writeFile "array.txt" (show [1,2,3])

Hugs> readFile "array.txt" >>= putStr
[1,2,3]

ファイル array.txt では、リストのデータを文字列に変換して記録されているので、read 関数で戻してやらないといけない。read 関数で戻すときにはどのようなデータ型に戻すのかを指定するキャスト (::[Int] など)が必要だ。

Hugs> do cs <- readFile "array.txt"; print (sum (read cs ::[Int]))
6

話がそれるが、show 関数は様々な型のデータを文字列に変換してくれるから、次の例のようにプログラムで処理したデータを表示する時に便利だ。

Hugs> putStr ("sum " ++ show [1,2,3] ++ " = " ++ show (sum [1,2,3]))
sum [1,2,3] = 6

ファイルの読み出しをすると、IOモナドの世界にワープしてしまって出られなくなるので、その後の処理もIOモナドの世界の関数 print などに関連付けてデータ処理をしなくてはならないので気をつけないといけない。といっても、return や putStr などのIOモナドの世界の関数の引数として記述すれば良いだけなので慣れの問題だけだ。

IOモナドの世界は変数のスコープに似ている。ブロックの内側から外の変数は見えるが、ブロックの外側からブロックの内側の変数を見ることはできない。同様に、IOモナドの世界からは、純粋関数の世界の関数を利用できるが、純粋関数の世界の関数からは、IOモナドのデータを利用することはできない。恐れられているIOモナドと言ってもプログラムで使うという目的からはその程度の理解で充分だ。

ファイルハンドルを使う場合

readfile.hs ファイルを読みだして表示するプログラム。

import IO

main = do putStr "filename: "
             fname <- getLine
             fromHandle <- openFile fname ReadMode
             contents <- hGetContents fromHandle
             putStr contents
             hClose fromHandle
実行例
Main> :e readfile.hs
Main> :l readfile.hs
Main> main
filename: readfile.hs
import IO

main = do putStr "filename: "
             fname <- getLine
             fromHandle <- openFile fname ReadMode
             contents <- hGetContents fromHandle
             putStr contents
             hClose fromHandle
書き込み用のファイルを開くときは openFile 関数のモードを WriteMode にする。書き込みには putStr ではなく、hPutStr アクションを使う。