Emacs
AdventCalendar
elisp
EmacsDay 3

連想リストのUPSERT

More than 1 year has passed since last update.

UPSERTとは

データが存在するかどうかをチェックし、存在すれば更新、存在しなければ挿入を行うという処理は、よく行われます。

リレーショナルデータベース(RDBMS)上のSQL言語では、こうした処理を一文で行うためのコマンドを俗にUPSERTと呼び、長年にわたって実装や標準化が望まれていました。UPSERTは結局、SQL:2003にてMERGE文という形で標準化され、Oracle DatabaseやMicrosoft SQL Server、IBM DB2などの主要なRDBMS製品で実装されるようになっています。

Emacs Lisp連想リストのUPSERT

UPSERTは、Emacsで連想リストを扱う場合でも使いたい場合があります。例えば、フレームの形状を設定する連想リストdefault-frame-alistでEmacsのフレームの幅を100に設定する場合です。
default-frame-alistwidthがすでに設定されている場合はwidthの値を100に更新し、設定されていない場合は(width . 100)default-frame-alistに挿入するという処理になります。しかし、こうした処理をいちいちinit.elなどの初期化ファイルに記述していったのでは、面倒ですし、初期化ファイルのメンテナンスもたいへんになります。そこで作ったのがEmacs Lispで連想リストのUPSERTを実現する次の関数update-or-add-alistです。

(defun update-or-add-alist (alist-var key value)
  "If KEY in ALIST, update VALUE of the KEY.
Unless, cons cell (KEY . VALUE) is added."
  (let (acell (alst (symbol-value alist-var)))
   (if (setq acell (assoc key alst))
       (unless (equal (cdr acell) value)
         (setcdr acell value))
     (set alist-var (push (cons key value) alst)))
   alst))

この関数を定義したあと、default-frame-alistでフレームの幅を100に設定するには、次のようにします。

(update-or-add-alist 'default-frame-alist 'width 100)

よければ、お試しください

おまけ

実は、こういう関数はすでに標準で存在しているはずなのに…といろいろ調べたのですがついに見つけられず、自分で実装したという経緯があります。心当たりの方がいれば、教えてください^^