• 作成:

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)

もしそれでもチェックしきれないデータの場合は、引数の内部で何かしらの識別子をチェックする必要があるでしょう。

余談

これ基礎的な知識だと思うんですが、何故か関連ワードで検索しても出てこなかったのでポインタとして記事を書いておきます。