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

时间:2016-03-04 23:02:05

标签: 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
        `((“one”“two”“three”)(“ten”,x“12”))
    注意:此版本中的,x。我希望在从文件中读取表达式后对其进行评估。
  2. parts/two.part
        ((“四”“五”“六”)(2 4 6)(9 87 6))
  3. parts/three.part
        ((“七”“八”“九”))
  4. 阅读“部分”文件没问题。 (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
    

1 个答案:

答案 0 :(得分:1)

Backquote做有趣的事情。在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。 Common Lisp使用逗号字符做了一些奇怪的事情,在读取相同列表后,X成为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进行替换,但它接受一个结构:它不会评估它的参数,所以要让它作用于{ {1}}必须执行以下操作:

x

正如您所见,ELISP> (let ((c 10)) (eval `(backquote ,x))) (a b 10) (\, c)的本地绑定所取代。

PPPS。人们会期望从字符串c(a b,c)中读取“"(反引号(a b,c))`但它不会。”

我希望这能提供答案。