emacs - 在 elisp 中,如何将反引号应用于从文件读取的列表

标签 emacs elisp

我想获取一个大列表(想想 emacs 主题中的面孔)并将其分解为单独文件中的较小列表。我遇到的问题是在读入列表后将(backquote)应用于列表。

这是我一直用来尝试解决方案的代码:

(defvar x 23)

(defun read-from-file (file)
  (with-temp-buffer
    (insert-file-contents file)
    (read (current-buffer))))

;;(defun apply-macro (macro arg-list)
;;  (eval
;;   `(,macro ,@(loop for arg in arg-list
;;                    collect `(quote ,arg)))))

(defvar parts (mapcar 'read-from-file (directory-files "./parts/" "parts/" "\.part$")))

;;(apply-macro 'backquote parts)

parts 

此代码依赖于名为 parts/ 的子目录中的“数据”文件。以下是一些示例:

  1. parts/one.part
    `((“一”“二”“三”)(“十”,x“十二”))
    注意:其中的,x。我想在从文件中读取表达式后对其进行评估。
  2. parts/two.part
    ((“四”“五”“六”)(2 4 6)(9 87 6))
  3. parts/Three.part
    ((“七”“八”“九”))

读取“部分”文件没有问题。 (defvar parts (mapcar ... ) 表达式有效。

问题是,一旦我在 parts var 中获得了列表,我就无法找到一种方法来评估 ,x ,就像整个列表一样被反引用并且未从文件中读取。

我已经尝试过a solution this question中建议。您可以在上面的代码中看到 apply-macro 函数被注释掉。当我运行它时,我得到:

Debugger entered--Lisp error: (wrong-number-of-arguments #[(structure) "\301!A\207" [structure backquote-process] 2 1628852] 3)
  #[(structure) "\301!A\207" [structure backquote-process] 2 1628852]((quote (\` (("one" "two" "three") ("ten" (\, x) "twelve")))) (quote (("seven" "eight" "nine"))) (quote (("four" "five" "six") (2 4 6) (9 87 6))))
  (backquote (quote (\` (("one" "two" "three") ("ten" (\, x) "twelve")))) (quote (("seven" "eight" "nine"))) (quote (("four" "five" "six") (2 4 6) (9 87 6))))
  eval((backquote (quote (\` (("one" "two" "three") ("ten" (\, x) "twelve")))) (quote (("seven" "eight" "nine"))) (quote (("four" "five" "six") (2 4 6) (9 87 6)))))
  apply-macro(backquote ((\` (("one" "two" "three") ("ten" (\, x) "twelve"))) (("seven" "eight" "nine")) (("four" "five" "six") (2 4 6) (9 87 6))))
  eval-region(648 678 t #[257 "\300\242b\210\301\207" [(678) (apply-macro (quote backquote) parts)] 2 "\n\n(fn IGNORE)"])  ; Reading at buffer position 651
  eval-defun-2()
  #[257 "\211\203

最佳答案

反引号做了有趣的事情。在 Emacs lisp 中,读取准引用列表的返回值是以下结构的列表:

ELISP> (defvar x (car (read-from-string "`(1 2 ,x)")))

ELISP> (car x)
\`

ELISP> (cdr x)
((1 2
    (\, x)))

ELISP> (caddr (cadr x))
(\, x)

ELISP> (consp (caddr (cadr x)))
t

因此,如果您打算使用准引用列表,您可能需要自行执行替换。例如,您可以这样做:

(defun replace-item (item new-item seq)
  (let ((found-item (member item seq)))
    (when found-item
      (setf (car found-item) new-item))
    seq))


ELISP> (replace-item '(\, x) 'z (cadr x))
(1 2 z)
PS。在阅读相同的列表 ,X 后,Common Lisp 对逗号字符做了一些奇怪的事情。成为 SB-IMPL::COMMA 类型的对象(在 SBCL 中):它既不是符号,也不是一对。

PPS。不知何故,这些准引号和逗号被读者评估者特殊对待,以至于组合 (eval (read <...>))不会产生与内部评估器相同的结果。

有用的东西

在使用反引号和逗号时,我发现以下方法可以工作,尽管它有点破解。

首先,不要反引用你的结构:它不会造成任何伤害,但也不会引入任何东西。只要有(a b ,c) .

当您读取它时(无论是使用文件中的 read 或使用 read-from-string ),它将转换为:

ELISP> (setq x (car (read-from-string "(a b ,c)")))
(a b
   (\, c))

现在,神奇的是:有宏 backquote它执行替换,但它接受一个结构:它不评估其参数,因此使其作用于 x必须执行以下操作:

ELISP> (let ((c 10)) (eval `(backquote ,x)))
(a b 10)

如您所见 (\, c)c 的本地绑定(bind)取代如所愿。

购买力平价。人们会期望从字符串 " 中读取内容(a b ,c)"would produce (反引号 (a b ,c))` 但事实并非如此。

我希望这能提供答案。

关于emacs - 在 elisp 中,如何将反引号应用于从文件读取的列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35807645/

相关文章:

emacs - 如何在 Emacs 中更改 [] 和 () 的颜色主题?

emacs - 如何让 Emacs 转换模式忽略出现在 virtualenv Cython 项目中的大多数文件?

file - Emacs 口齿不清 : How can I get the newest file in a directory?

emacs - 使用区域缩进函数保持区域标记

python - 用于列出 python 模块中所有方法的 Emacs 插件

emacs - 保存和恢复 elscreen 标签和分帧

Elisp:无法掌握 setq 和 sort 的效果

google-chrome - 从 Emacs 远程控制 Chrome/Chromium 浏览器?

bash - Emacs lisp -- 如何将 `&&` 提交给 shell?

emacs - 连接来自不同目录的 TAGS 文件的内容