使用elisp局部变量而不是全局变量将函数添加到模式钩子中



所以我试图添加一些东西到一些elisp模式钩子-具体来说,我想定义一个钩子的prettify-symbols-alist,然后通过调用prettify-symbols-mode专门激活它。

在任何情况下,我得到org-babel导出值到一对列表从一个表,使用pairlis将它们捆绑在一起作为一个列表,和add-hook它到使用匿名函数所需的模式。

问题是,现在如果我使用一个全局变量,就像下面这样,它工作了:

(let ((token (quote ("not" "*" "/" "->" "map" "/=" "<=" ">=" "lambda")))
      (code (quote (172 215 247 8594 8614 8800 8804 8805 955)))) ; Generated automatically using org-babel
  (require 'cl)
  (setq *globalvar (pairlis token code))
  (add-hook 'emacs-lisp-mode-hook
            (lambda ()
               (setq prettify-symbols-alist *globalvar)
               (prettify-symbols-mode 1))))

但是如果我尝试不使用全局变量,通过这样做,它不起作用:

(let ((token (quote ("not" "*" "/" "->" "map" "/=" "<=" ">=" "lambda")))
      (code (quote (172 215 247 8594 8614 8800 8804 8805 955)))) ; Generated automatically using org-babel
  (let (localv)
    (require 'cl)
    (setq localv (pairlis token code))
    (add-hook 'emacs-lisp-mode-hook
              (lambda ()
                 (setq prettify-symbols-alist localv)
                 (prettify-symbols-mode 1))))

我有点知道为什么:如果我C-h v emacs-lisp-mode-hook,我会看到它指的是我在let形式中使用的任何变量,当变量存在时,如*globalvar,但当我使用localvar时,它不再存在于其let形式之外。但是我不确定如何强制对局部变量本身进行评估,因为我仍然在努力解决lisp中的许多概念,这些概念对我来说不是很清楚。

我错过了什么?我哪里出错了?

好了,这是我最后做的:

(let ((token (quote ("not" "*" "/" "->" "map" "/=" "<=" ">=" "lambda")))
      (code (quote (172 215 247 8594 8614 8800 8804 8805 955))))
  (require 'cl)
  (lexical-let (localv)
    (setq localv (pairlis token code))
    (add-hook 'emacs-lisp-mode-hook
               (lambda ()
                  (setq prettify-symbols-alist localv)
                  (prettify-symbols-mode 1)))))

我最终使用phils的建议使用lexical-let而不是Drew的建议,主要是因为我目前使用org-babel将代码块缠结到我的源代码中(基本上我使用org-mode来组织我的设置文件),并且似乎没有办法设置lexical-binding文件本地变量-根据本页,您需要将其设置为第一行(使用;; -*- lexical-binding: t -*-),我找不到一种方法来做到这一点。

无论如何,感谢每个帮助我解决这个问题的人!

首先将lexical-binding设置为非nil,否则localv将成为钩子函数中的自由变量。最好将lexical-binding设置为文件本地变量。

此外,代码中没有任何内容使localv buffer-local。假设你想给它一个值,这个值对于处于该模式的缓冲区来说是局部的。绑定它的代码应该在模式中(即在缓冲区中)进行计算。

我喜欢这个解决方案。对于lexical-let,对lambda的调用(在add-hook内部)生成一个闭包,正如您可以看到的,如果您输入M-x ielm RETemacs-lisp-mode-hook RET来检查它的值。

你也可以像这样使用老式的反号:

(add-hook 'emacs-lisp-mode-hook
           `(lambda ()
              (setq prettify-symbols-alist ',localv)
              (prettify-symbols-mode 1)))

(编辑)

注意backticklambda之前,(如tarikq所提到的)quote-commalocalv之前。

我想你明白我的意思了!

实际上,我要说的不是"展开它然后引用它",而是"插入它的值(来自词法环境),然后引用它"。

如果你尝试这样做:

 (macroexpand '`(lambda ()
                  (setq prettify-symbols-alist ',localv)
                  (prettify-symbols-mode 1)))

那么你将得到lisp在运行时实际执行的操作:

 (cons 'lambda
      (cons nil
            (cons
             (list 'setq 'prettify-symbols-alist (list 'quote localv))
             '((prettify-symbols-mode 1)))))

,您将看到整个列表是如何构建的,以及localv通常如何求值,即不引用(与符号'setq'prettify-symbols-alist以及列表'((prettify-symbols-mode 1))相比)

最新更新