一千萬個為什麽

搜索

如何報價多級宏擴展

我是Emacs的新手,並認為我遇到了一些宏擴展問題。有一個函數 solarized-with-color-variables ,它是一個使用 let * 創建局部變量的宏,然後在 let * <�內擴展宏體參數/ code> body,以便它可以訪問這些變量。

有一點我需要 setq 一個變量到一個由列表組成的值,其中第一個元素應該取這些變量之一的值, green 。通常我這樣做:

(setq some-var `(,green box))

但是,似乎在切換到使用 use-package.eluse-package 宏之後,好像我現在處於多層宏中,這樣以上現在再擴展一次:

(setq some-var (green box))

也就是說,它試圖將 green 稱為函數,而不是;這是一個字符串。

我不知道如何解決這個問題,或者我該如何處理。我的猜測是我必須將它基本上包裝在另一層引號中,以便額外的擴展保持原樣,但是對Emacs Lisp來說是新手我不太確定如何做到這一點。我嘗試了幾種 quotelist 的變體無濟於事。

;; use-package is a macro
(use-package solarized-theme
  :ensure t
  :config
  (load-theme 'solarized-light t)

  ;; solarized-with-color-variables is a macro
  (solarized-with-color-variables 'light
    (custom-theme-set-faces
     'solarized-light
     `(show-paren-match ((,class (:foreground unspecified
                                  :background ,base02
                                  :weight normal)))))

    ;; I wanted to use with-eval-after-load but that's also a macro
    (eval-after-load 'evil
      (progn
        (setq some-var `(,green box))))))

Edit: I've come to realize that it is the eval-after-load function I'm using.

如果我有這個:

(solarized-with-color-variables 'light
    (setq evil-emacs-state-cursor `(,red box)))

一切正常。但是,如果我把它放在 eval-after-load 中,反之亦然,它會破壞:

(eval-after-load 'evil
    (solarized-with-color-variables 'light
        (setq evil-emacs-state-cursor `(,red box))))

它表示 red ,“#blah”的值不是有效的函數。我想它正在擴展宏兩次,一次用於 solarized-with-color-variables ,這樣它就可以產生:

(setq evil-emacs-state-cursor '("#blah" box))

然後再次(?):

(setq evil-emacs-state-cursor ("#blah" box))

然後在嘗試評估它時,它嘗試使用“#blah”作為函數,但事實並非如此。使用我自己的答案中的代碼實際上也給了我一些問題,我想這與我手動設置的值不完全相同,即'(“#blah”box)

(setq some-var `(list ,green 'box))

最佳答案

應該刪除 eval-after-load

(use-package solarized-theme
  :ensure t
  :config
  ...
  ;; solarized-with-color-variables is a macro
  (solarized-with-color-variables 'light
    ...
    (setq some-var `(,green box))))

它表示紅色的值“#blah”不是有效的功能。我想它正在擴展兩次宏,一次是用於顏色變量的曝光,以便產生:

它將綠色稱為函數,但不是因為嵌套宏,而是因為 eval-after-load函數,並且函數在調用之前會對其參數進行求值,所以當你打電話

(eval-after-load 'evil
  (progn
    (setq some-var `(,green box))))

它首先評估 progn ,它將 some-var 設置為列表(“#859900”框)並返回該值(因為 setq 返回它設置的值)。 eval-after-load 的第二個參數應該是一個要評估的表單,因此在加載 evil 之後它會嘗試計算(“#859900”框) )作為一個表單,即將第一個元素作為一個函數調用,當然這個函數失敗了。

通常你應該引用你傳遞給 eval-after-load 的表單,但在這種情況下會阻止 green 被替換,因為在評估發生時就會消失。 如果你在init文件的頂部設置了 lexical-binding:t ,你可以改用lambda:

(eval-after-load 'evil
  (lambda ()
    (setq some-var `(,green box))))

這與使用 with-eval-after-load 相同:

(with-eval-after-load 'evil
  (setq some-var `(,green box)))

如果你不使用詞法綁定,你可以通過構造要評估的列表來偽造它:

(eval-after-load 'evil
  `(setq some-var '(,green box)))

但由於您通常不需要延遲 setq 變量,因此完全刪除後加載的內容對於這種特殊情況最為簡單。

轉載註明原文: 如何報價多級宏擴展