ujimushi(@旧sradjp(15364))の日記

旧スラドの日記の引越先です

EmacsのEllamaでemacs-lispのソースを解説してもらう

Ellamaの使い方とかあまり分かっていませんでしたが, 私的にはソースリーディングにすごく役立ちそうでした。

今まで中身がよく分かっていなかったtc.elの中身とか解説してもらうと便利そうです。

モデルは目的と評判と諸々の事情(GPUのメモリ量)からqwen2.5-coder:7b-instructを使っています。

使用例

まず,解説して欲しい関数をtcソースコードの該当部分をリージョン選択して ellama-context-add-selection関数を実行します。

この時ちゃんと選べたかどうかのリアクションが返ってこないので,やや不安…

その後,ellama-chatで「~の関数について詳細に説明して下さい」 とかやるとその関数について説明してもらえます。

次が実行列です。chatのバッファは標準ではorg-modeなのですがmarkdown-modeに変更しています。

なお,二回目にやって必ずこの回答が得られるかどうかは分からないです。 英語の回答が返ってきた時は,「さっきの回答を日本語で…」みたいな感じでやると 日本語に翻訳して返してくれます。

## User:
Context:
(defun tcode-subtract-set (list1 list2)
  (if list2
      (let ((l1 (copy-sequence list1))
        (l2 (copy-sequence list2))
        ci)
    (while (and l1 l2)
      (let* ((e (car l1))
         (c1 (tcode-count e l1))
         (c2 (tcode-count e l2))
         (diff (- c1 c2)))
        (if (> diff 0)
        (setq ci (nconc ci (make-list diff e))))
        (setq l1 (delq e l1)
          l2 (delq e l2))))
    (nconc l1 ci))
    list1))


emacs-lispの関数である`tcode-subtract-set`について詳細に説明して下さい

## Ellama:
`tcode-subtract-set` は Emacs Lisp の関数で、2つのリスト `list1``list2` を引数として取り、`list1` から `list2` で指定された要素を差し
引く操作を行います。具体的には、`list1` 中の各要素が `list2` で何回現
れるか比較し、`list2` での出現回数より多い場合のみ、その要素が残ります。

以下にこの関数の詳細な解説を提供します:

### 関数定義
```emacs-lisp
(defun tcode-subtract-set (list1 list2)
```
- `tcode-subtract-set``list1` から `list2` の要素を差し引く関数で
  す。

### 条件処理
```emacs-lisp
  (if list2
      ...
    list1))
```
- もし `list2` が空(`nil`)でない場合、以下の処理を行います。
- `list2` が空の場合、そのまま `list1` を返します。

### 変数初期化
```emacs-lisp
  (let ((l1 (copy-sequence list1))
        (l2 (copy-sequence list2))
        ci)
```
- `l1``l2``list1``list2` のコピーを作成します。
- `ci` 是空のリストで、差し引く要素を格納します。

### ループ処理
```emacs-lisp
    (while (and l1 l2)
      (let* ((e (car l1))
             (c1 (tcode-count e l1))
             (c2 (tcode-count e l2))
             (diff (- c1 c2)))
        (if (> diff 0)
            (setq ci (nconc ci (make-list diff e))))
        (setq l1 (delq e l1)
              l2 (delq e l2))))
```
- `while` ループを使用して、`l1``l2` の両方が空になるまで処理を行
  います。
- 各反復で、`l1` の先頭の要素を `e` に設定します。
- `tcode-count` 関数を使用して `e``l1` 中と `l2` 中でそれぞれ現れ
  る回数を計算します。
- 現在の差 `diff` を計算します (`c1 - c2`)。
- `diff` が正(つまり、`list1` 中での出現回数の方が多ければ)の場合、
  `make-list diff e` を生成して `ci` に追加します。
- `e``l1``l2` から削除されます。

### 結果の組み合わせ
```emacs-lisp
    (nconc l1 ci))
```
- 最後に、`list1` の残り部分 (`l1`) と差し引く要素 (`ci`) を結合して結
  果を返します。

### 使用例
```emacs-lisp
(tcode-subtract-set '(a b c a) '(a b))
;; => (c a)
```

この関数は、`list1` 中の各要素が `list2` で何回現れるか比較し、その差
を計算することで、必要な要素だけを残すことができます。

いや~emacs-lsip読むの苦痛だから日本語でちょっとした解説もらえるの嬉しいわ~。 といった感じでtc.elの部首合成部分についてどんな動きになっているのか アシストしてもらっている感じです。

そしてネットをググっていて今さら気がついたのですが,コンテキストサイズ(無設定の時は2048)を個別に設定できるようですね。 例えば次のような感じにすると32kにできるようです。

qwen2.5-coderの7bは本来128kと書いてあるのですが,ollamaに登録されているものは32kに制限されてそうです。 それでも32kあるので小さいソースファイルならcontextにファイルまるごと読み込ませた方が手間がかからなそうです。

  (setopt ellama-provider
      (make-llm-ollama
       :chat-model "qwen2.5-coder:7b-instruct"
       :embedding-model "qwen2.5-coder:7b-instruct"
       :default-chat-non-standard-params '(("num_ctx" . 32768))
       ))

Emacs Lispに詳しい人って身近にいないので,(Emacsを使っている人が周りにいないとも言う)すごく便利に使えそうです。

追記

記事を書いて後で調べ直して気付いたのですが,コンテキストサイズを大きくすると必要なメモリ量が極端に大きくなるようなので,実行環境のGPUメモリ等をふまえて適切に設定するのがいいかと思います。

私の場合,CPU側のメモリは64GBあるのでそちらの容量でカバーして処理されているような気がします。時々処理速度が非常に遅くなることがあるので。