数値のリストををcsvファイルに出力する
Text.CSV を使えば csv ファイルを書き出せるのですが、String の要素にしか対応していません。数値であっても一度 String に変換しないといけないので、コードも結果も不格好です。
import Text.CSV putStrLn . printCSV $ fmap (fmap show) [[1,2,3], [4,5,6]]
"1","2","3" "4","5","6"
そこで、数値を String に変換しないものを作ってみようと思います。
newtype Rec a = Rec [[a]] joint :: String -> [String] -> String joint = intercalate printRec :: Show a => Rec a -> String printRec (Rec xss) = joint "¥n" $ fmap (joint "," . fmap show) xss
joint を定義せずに intercalate のまま使っても良いのですが、どうも読んでいてしっくりこないのでこうしました。ためしてみましょう。
> putStrLn $ printRec (Rec [[1,2,3],[4,5,6]]) 1,2,3 4,5,6
良さそうです。ファイルに出力したければ、writeFile に喰わせてあげればOKです。今回は a -> String を show 関数に任せましたが、Text.Printf を使って書式を指定することもできると思います。
では。
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 で包んで完成です。
とりあえずここまで。
答えはいくつあるのか?
数学の本を読んでいると、直感的でないと思えるような表現が出てくることが時々あります。今回は、「ある条件を満たすものがいくつあるか」という話です。
例えば、モノ射の定義は以下のように書かれています。
任意の圏Cにおいて、射 f : A → B が、
任意の射 g, f : C → A が与えられたとき、fg = fh なら g = h となるとき、
fはモノ射である。
最初に読んだとき、この「fg = fh なら g = h」が何を言いたいのか全くつかめませんでした。とっても難しいことが書いてある感じがして、もうパニックです。
でも落ち着いて、出来るだけ日本語にして読んでみると……同じ性質のものが2つ(ここでは f, g)あったとしたら、それは実は同じものなんだよ、と言っているだけのようです。ということは、「2個以上あるようにみえたとしたら、それは実は1個」、つまり「0個か1個」ということですね。
そう書かないのは元の表現が便利だからなのでしょうが、素人はこういうところからつまずいていくのです。
そうすると、他の個数の場合はどう表現するのかが気になります。多分、こんな感じでしょう。
- 0個の場合 : 存在しない
- 1個の場合 : 存在してかつ一意
- 0 or 1個の場合 : 2個存在するならそれらは等しい
- 1個以上 : 存在する
他の表現が見つかったら、また書きます。
明けましておめでとうございます。
2015年は、いくつかの巡りあわせのおかげで、趣味で数学をはじめた年でした。
本を読み、疑問をもち、解決して理解を深める、というプロセスを自分のペースで進められるのは、趣味として最適です。さらに、最近はネットでも数学愛好家の方々が面白い記事を上げているので、とても参考になります。
とはいえ、気になるポイントは人によって違いますから、私の抱いた疑問について説明がみつからないこともあります。
このブログでは、そんな疑問についての、自分なりの理解を書いていこうと思います。