Haskellからデータベース接続
apt-get install libghc6-haskelldb-dev
関連パッケージがもさもさっとインストールされる。
やたら沢山ある。
使い方はこの辺
HaskellDB
使い方
テーブル定義の作成
まずはテーブル定義ファイルを作成する。
module DBSpec where import Database.HaskellDB.DBSpec import Database.HaskellDB.FieldType import Database.HaskellDB.DBSpec.DBSpecToDBDirect dbInfo = DBInfo { dbname = "username", opts = DBOptions {useBString = False}, tbls = [myTable] } myTable = makeTInfo "tablename" [tRow1, tRow2] tRow1 = makeCInfo "column1" (StringT, True) tRow2 = makeCInfo "column2" (StringT, True) createDBInfo = dbInfoToModuleFiles "" "DBInfo" dbInfo
だいたい見ての通り。
DBOptionsはよく分からない・・。
(StringT, True)のTrueは、nullが含まれるかどうか。
これをTrueにすると、値はMaybe型で返ってくる。
そして
import DBSpec main = createDBInfo
でテーブル定義ファイルを作成する。
これを実行すると自動的に(上の例では)DBInfo/Tablename.hs が生成される。
DBの利用
import Database.HaskellDB import Database.HaskellDB.GenericConnect import DBInfo.Tablename dbDriver = "postgresql" dbServer = "localhost" dbDatabase = "dbname" dbPassword = "" dbUsername = "username" withDB q = genericConnect dbDriver [dbServer,dbDatabase,dbPassword,dbUsername] (printAndPerformQuery q) printAndPerformQuery q db = do putStrLn "Query:" print q result <- query db q putStrLn "Results:" mapM_ print result selectAllFromMyTable = table tablename main = withDB selectAllFromMyTable
取り敢えず例題をそのままコピってみた。
型を細かく見てみると
main = mapM_ print =<< getAllData getAllData = conn tableDataQuery conn :: (Database -> IO a) -> IO a conn f = genericConnect dbDriver [dbServer,dbDatabase,dbPassword,dbUsername] f --tableDataQuery :: Database -> IO a tableDataQuery db = query db (table tablename)
このようになる。
tableDataQueryの戻り値はIO [Record ...]になる。細かい定義は makeTInfo で作ったファイルに基づく。
細かいデータベース処理は隠蔽されているので、queryに渡す関数を定義していくことになるのかな。
main = mapM_ print =<< getAllData -- -- データベースクエリ関数 -- getAllData = genericQuery getAllDataQuery getAllDataQuery = table tablename -- -- 汎用操作 -- genericQuery = conn . result conn :: (Database -> IO a) -> IO a conn = genericConnect dbDriver [dbServer,dbDatabase,dbPassword,dbUsername] result f db = query db f
こんな感じで。
Haskellの基本
emacsはカーソルを合わせるだけで型が表示されるので凄く便利。
. :: (b -> c) -> (a -> b) -> a -> c
みたいな。
この辺の基本的なところでよく悩む・・。
main = f 1 >>= print f n = g $ h n f' n = (g . h) n f'' n = g . h -- $ :: (a -> b) -> a -> b g :: String -> IO String g = return . (++ "a") h :: Int -> String h = show
$ の右に来る関数は、部分適用じゃダメ。
言い換えると、. の右に来る関数は変数を一つ取る関数。
・・・・っていうのは、頭では分かっていたのに実感として持ててなかった。
自分で書いておきながら、さっきの
genericQuery = conn . result
で悩んでしまった。
genericQuery :: Query -> Database -> IO a
になって(実際に書くとエラーになるけど)、Queryに適用させると (Database -> IO a)の関数になり、genericConnectを適用できるようになる。
うーん・・適用っていう言葉の使い方が間違ってるっぽい雰囲気。
本に書いていた
map ($ 0) xs zipWith ($) fs xs
の使い方も謎・・奥が深い。
xreaでHaskell
コメントをいただきまして(http://d.hatena.ne.jp/n314/20060917/1158475378#c)
無事xreaでHaskellを動かすことができた。
どうやら完全にスタティックリンクするには -optl-static オプションが要るらしい。
http://www.haskell.org/pipermail/glasgow-haskell-users/2006-January/009545.html
この辺かな?
Haskellじゃないオブジェクトとスタティックリンクするには -optl-static をつけなさいということらしい。(たぶん
http://www.n314.com/Haskell/wiki/
バグが多々あるような気もするしコードは汚いし、っていうので実用的じゃないけれど取り敢えず進捗をアップ。