Emacs Lispでリストに対して要素を重複せずに追加する
問題
トップレベルのautoloadコードなど何回実行されるかよく分からない場所のコードで、リストに対して要素を追加する場合、何度実行されても構わないように要素が重複しないように追加したい。
おなじみのadd-to-list
を使うだけでは目的が達成できない時があります。
add-to-list
が重複をチェック時に使う基準はシンボル単位のようなので、データの型によっては毎回データを生成している場合重複していないと判断されて毎回追加されてしまうことがあります。
解決策
add-to-list
にもCOMPARE-FN
引数があるので、そこで比較関数を指定することで解決は可能です。
しかしマニュアルにcl-lib
に定義されているcl-pushnew
を使ったほうが良いと書かれてあるので、そちらを使うことにします。
cl-pushnew
自体は要素を追加するだけですが、
:test
引数をサポートしているので、ここに:test #'equal
を指定してやれば、大抵の重複は防げるでしょう。
実例を以下に示します。
;; Top-level execute code.
;;;###autoload
(cl-pushnew
(make-copilot-chat-frontend
:id 'shell-maker
:init-fn #'copilot-chat-shell-maker-init
:clean-fn #'copilot-chat--shell-maker-clean
:format-fn nil
:format-code-fn #'copilot-chat--markdown-format-code
:create-req-fn nil
:send-to-buffer-fn nil
:copy-fn nil
:yank-fn nil
:write-fn nil
:get-buffer-fn #'copilot-chat--shell-maker-get-buffer
:insert-prompt-fn #'copilot-chat--shell-maker-insert-prompt
:pop-prompt-fn nil
:goto-input-fn #'nil
:get-spinner-buffer-fn #'copilot-chat--shell-maker-get-buffer)
copilot-chat--frontend-list
:test #'equal)
もしそれでもチェックしきれないデータの場合は、引数の内部で何かしらの識別子をチェックする必要があるでしょう。
余談
これ基礎的な知識だと思うんですが、何故か関連ワードで検索しても出てこなかったのでポインタとして記事を書いておきます。