Haskell です.
前回の簡易KVSに, ファイルからのロード, セーブを追加. 操作を破壊的にしたもの.
kvs.hs : ソース
import System.IO import Data.List import Data.IORef -- print an IORef object p r = readIORef r -- display contents of a file cat fn = do h <- openFile fn ReadMode hGetContents h >>= putStr hClose h -- to bind variable, use like 'r <- load filename' -- r will be the type of IORef [(Int,String)] load myRead fn = do h <- openFile fn ReadMode c <- hGetContents h newIORef $ myRead c save fn r = do h <- openFile fn WriteMode c <- readIORef r hPrint h c hClose h new = newIORef [] ins e r = modifyIORef r (e:) lup k r = do t <- readIORef r return (lookup k t) upd (k,v) r = modifyIORef r ((\(l, r) -> l ++ (k, v):tail r) . break ((k ==) . fst)) del k r = modifyIORef r ((\(l, r) -> l ++ (tail r)) . break ((k ==) . fst))
「IORef a 型の値」(a は任意の型) を第一引数, 「a 型の値を引数にとって a 型の値を返す関数」を第二引数に modifyIORef を呼び出すと, IORef で参照される値が変更されます.
ので, 前回との違いは,
del k t = (\(l, r) -> l ++ (tail r)) $ break ((k ==) . fst)
のように引数 t を変更した新しいテーブルを返すように書いていた関数を以下のように書き換えます.
すなわち, 左辺で, t を newIORef を使って, IORef 型にした変数 r を使います.
右辺では第一引数を r として, 第二引数を元の関数の右辺として, modifyIORef を呼び出します.
del k r = modifyIORef r ((\(l, r) -> l ++ (tail r)) . break ((k ==) . fst))
test.kvs : テスト用ファイル
[(1, "foo"), (2, "bar"), (3, "baz")]
使ってみます.
% ghci GHCi, version 6.10.4: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer ... linking ... done. Loading package base ... linking ... done. Prelude> :l kvs.hs -- 上記ソースをロードします. [1 of 1] Compiling Main ( kvs.hs, interpreted ) Ok, modules loaded: Main. *Main> cat "test.kvs" -- ファイルの中身を確認 [(1, "foo"), (2, "bar"), (3, "baz")] *Main> r <- load (read::String -> [(Int,String)]) "test.kvs" -- test.kvs の中身を [(Int,String)] として解釈し, r に束縛 *Main> p r [(1,"foo"),(2,"bar"),(3,"baz")] *Main> ins (4,"qux") r -- (4, "qux") を挿入 *Main> p r [(4,"qux"),(1,"foo"),(2,"bar"),(3,"baz")] *Main> lup 2 r -- キーが 2 であるエントリを検索 Just "bar" *Main> lup 5 -- キーが 5 であるエントリを検索 -- Nothing が返されたときの対処をしていないので <interactive>:1:0: -- 実行時例外 No instance for (Show (IORef [(t, b)] -> IO (Maybe b))) arising from a use of `print' at <interactive>:1:0-4 Possible fix: add an instance declaration for (Show (IORef [(t, b)] -> IO (Maybe b))) In a stmt of a 'do' expression: print it *Main> upd (2,"quux") r -- キーが 2 であるエントリの値を "quux" に変更 *Main> p r [(4,"qux"),(1,"foo"),(2,"quux"),(3,"baz")] *Main> del 1 r -- キーが 1 であるエントリを削除 *Main> p r [(4,"qux"),(2,"quux"),(3,"baz")] *Main> save "test2.kvs" r -- "test2.kvs" に保存 *Main> cat "test2.kvs" -- "test2.kvs" の中身を確認 [(4,"qux"),(2,"quux"),(3,"baz")]
追記: 2010.11.26
これ KVS って言わないよな… タイトルから来た方すいません.
Related Posts:
- GHCiで簡易KVS
- ハノイとバベルの塔 第六階 – 端末アニメ in Java
- ハノイとバベルの塔 第九階 – 端末アニメ in Clojure
- Unchecked cast
- ハノイとバベルの塔 第五階 – 端末アニメ in C