Text.CSV を使う
純粋型言語で副作用を許さないのなら、入出力はどうするの?
と思っていた時期がありました。
細かい理屈はさておき、Haskell でもファイルの読み書きは出来ることがわかったので、書いておくことにします。
使ったのは Text.CSV。最初に、ここで定義されている関数を hackage でチェックします。どうやらprintCSVがそれっぽいのですが、引数がCSV型のようです。
そこで CSV の定義を同じページで見てみると、
type CSV [Record] type Record [Field] type Field [String]
とたどっていけます。要するに CSV は String ということのようです。数値を出力したい場合は、何か追加しないとだめだと分かりました。
これは後で対応するとして、まずはprintCSVの味見をしてみます。
writeFile "data.txt" $ printCSV [["a", "b", "c"], ["d", "e", "f"]]
出来た。
ついでに、棚上げしていた数値の出力についても。
printCSV が CSV しか受け取れないので、任意の型をとれる二重リストとして Rec をつくって見ましょう。必要なのは Rec の定義と、それを CSV に渡すために a にほどく関数です。
newtype Rec a = Rec [[a]] fromRec (Rec xss) = xss
Rec を type でなく newtype にしたのは、いずれ fmap とかも定義したいからです。ただ、二重リストの fmap をどのように定義すべきかは悩みどころでした。受け取った関数を全要素に適用するのか、一列目だけがよいのか......
今回は練習用として、全部の要素にたいして単純に適用するとしてみました。
instance Functor Rec where fmap f (Rec xss) = Rec $ map (map f) xss
Rec を二重リストにほどいて xss とし、受け取った関数 f をリストに適用出来るようにして(内側のmap)、さらにそれを二重リストに適用します(外側のmap)。
ここまでだと a 型がかえりますので、最後に Rec で包んで完成です。
とりあえずここまで。