在 elisp 中,如何将反引号应用于从文件中读取的列表
In elisp, how do I apply backquote to lists read from files
我想获取一个大列表(想想 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/
的子目录中的 "data" 个文件。以下是一些示例:
parts/one.part
`( ("one" "two" "three") ("ten" ,x "twelve") )
注意:这一个中的 ,x
。我想在从文件中读取表达式后对其求值。
parts/two.part
( ("four" "five" "six") (2 4 6) (9 87 6) )
parts/three.part
(("seven" "eight" "nine"))
读取"part"个文件没有问题。 (defvar parts (mapcar ... )
表达式有效。
问题是,一旦我在 parts
var 中有了列表,我就无法找到一种方法来评估 ,x
,就像如果整个列表被反引号而不是被读取一样来自文件。
我试过了a solution suggested in this question。你可以在我上面的代码中看到 apply-macro
函数被注释掉了。当我 运行 我得到:
Debugger entered--Lisp error: (wrong-number-of-arguments #[(structure) "1!A7" [structure backquote-process] 2 1628852] 3)
#[(structure) "1!A7" [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 "02b017" [(678) (apply-macro (quote backquote) parts)] 2 "\n\n(fn IGNORE)"]) ; Reading at buffer position 651
eval-defun-2()
#[257 "13
反引号做了有趣的事情。在 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。 reader-求值器以某种方式对这些准引号和逗号进行了特殊处理,以至于组合 (eval (read <...>))
不会产生与内部求值器相同的结果。
有用的东西
在尝试使用反引号和逗号时,我发现以下内容有效,尽管它有很多 hack。
首先,不要反引用你的结构:它不会造成任何伤害,但也不会引入任何东西。只要 (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
的本地绑定。
PPPS。人们会期望从字符串 "
(a b ,c)"would produce
(backquote (a b ,c))` 中读取,但事实并非如此。
我希望这能提供答案。
我想获取一个大列表(想想 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/
的子目录中的 "data" 个文件。以下是一些示例:
parts/one.part
`( ("one" "two" "three") ("ten" ,x "twelve") )
注意:这一个中的,x
。我想在从文件中读取表达式后对其求值。parts/two.part
( ("four" "five" "six") (2 4 6) (9 87 6) )parts/three.part
(("seven" "eight" "nine"))
读取"part"个文件没有问题。 (defvar parts (mapcar ... )
表达式有效。
问题是,一旦我在 parts
var 中有了列表,我就无法找到一种方法来评估 ,x
,就像如果整个列表被反引号而不是被读取一样来自文件。
我试过了a solution suggested in this question。你可以在我上面的代码中看到 apply-macro
函数被注释掉了。当我 运行 我得到:
Debugger entered--Lisp error: (wrong-number-of-arguments #[(structure) "1!A7" [structure backquote-process] 2 1628852] 3)
#[(structure) "1!A7" [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 "02b017" [(678) (apply-macro (quote backquote) parts)] 2 "\n\n(fn IGNORE)"]) ; Reading at buffer position 651
eval-defun-2()
#[257 "13
反引号做了有趣的事情。在 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。 reader-求值器以某种方式对这些准引号和逗号进行了特殊处理,以至于组合 (eval (read <...>))
不会产生与内部求值器相同的结果。
有用的东西
在尝试使用反引号和逗号时,我发现以下内容有效,尽管它有很多 hack。
首先,不要反引用你的结构:它不会造成任何伤害,但也不会引入任何东西。只要 (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
的本地绑定。
PPPS。人们会期望从字符串 "
(a b ,c)"would produce
(backquote (a b ,c))` 中读取,但事实并非如此。
我希望这能提供答案。