Emacs LispにおけるS式のファイル書き出しと読み込み

連休はEmacs Lispに始まり,Emacs Lispに終わりそう.

PerlにおけるStorable,RubyにおけるMarshal,PythonにおけるPickleのようなデータ構造をそのままダンプする仕組みが欲しいというときにはLispは便利.S式をそのまま読み書きすればよい.(S式のバイナリダンプではないので,YAMLと言った方が正確)

S式の便利なところはデータ構造 = 記号であること.そのまま出力すればよい.
とりあえず,適当にデータとそれを保存する関数と読み込む関数を作ってみる.

(setq data '(((name . "hoge")
              (id   . 10))
             ((name . "fuga")
              (id   . 11))))

(defun save-data (filename)
  (interactive "sInput filename: ")
  (with-temp-buffer
    (insert (format "%s" data))
    (write-file filename)))

(defun read-data (filename)
  (interactive "sInput filename: ")
  (with-temp-buffer
    (insert-file-contents filename)
    (goto-char (point-min))
    (insert "(setq hoge '")
    (goto-char (point-max))
    (insert ")")
    (eval-buffer))
  (insert (format "%s" hoge)))
; 実行確認
> (save-data)
nil  ; hoge.datにdataのS式が書き出される

> (read-data "hoge.dat")
(((name . hoge) (id . 10)) ((name . fuga) (id . 11)))

; hogeの内容を確認
> hoge
(((name . hoge) (id . 10)) ((name . fuga) (id . 11)))

(with-temp-buffer)は,一時的なバッファをつくってカレントバッファに切り替えるというもので (save-excursion)+(swith-to-buffer)+(kill-buffer) のような使い方ができる.

save-dataはそのまんま.dataをそのまま一時バッファに書き込んでファイル出力をする.
read-dataでは,(with-temp-buffer (insert-file-contents filename))というコンボを使って一時バッファにファイル内容を読み込んでいる.

ここから先がよくわからなかった.本当はファイルに書き込まれた内容を評価 (e.g., eval, eval-last-sexp) して値を取得したかったのだけれど,evalは評価した値を返すわけではないらしく,うまく取得することができなかった.

結局,データを格納したい変数にsetqするという記述を追加してevalする方法で切り抜けたけれど,これだったら書き出す際に "(setq data '" という記述を加えた方が楽だったなぁと思ったり.

実は文字列をシンボルに変換する方法がわからなかったり,いろいろ未解決の問題がある.