在elisp中,如何对从文件读取的列表应用反引号 [英] In elisp, how do I apply backquote to lists read from files
问题描述
(backquote)
应用于列表。 这里是我一直在使用代码来尝试解决方案:
(defvar x 23)
(defun从文件(文件)
(with-temp-buffer
(插入文件内容文件)
(read(current-buffer))))
;;(defun apply-macro(macro arg-list)
;;(eval
;;((宏,@(循环for arg在arg-list
;; collect `(quote,arg)))))
(defvar parts(mapcar'read-from-file(directory-files./parts/parts /\.part $ ))
;;(apply-macro'backquote parts)
parts
此代码依赖于名为 parts /
的子目录中的数据文件。以下是一些示例:
-
parts / one.part
`((onetwothree)(ten,x12))
注意:,x
在这一个。我想在表达式从文件中读取后进行评估。 -
parts / two.part
((fourfivesix)(2 4 6)(9 87 6)) -
parts / three.part
((七八九))
阅读零件文件是没有问题的。 (defvar parts(mapcar ...)
表达式。
问题是一旦我有列表在部分
var中,我找不到一种方法来获取,x
,因为它将是整个列表已经被引用并没有从文件中读取。
我已经尝试过解决方案a>在此问题中建议您可以看到上面我的代码中注释的 apply-macro
函数,当我运行它时,我得到:
调试器输入 - Lisp错误:(错参数#[(结构)\301!A \207[结构反引号过程] 2 1628852] 3)
#[(结构)\301!A \207[结构反引号过程] 2 1628852]((引号(\((一两三)(十 (\,x)十二))))(quote((七八九)))(引号((四五六 2 4 6)(9 87 6))))
(backquote(quote(\`((onetwothree)(ten(\,x)12) )(quote((789)))(quote((fourfivesix)(2 4 6)(9 87 6))))
eval((( 9)()((四五六)(2 4 6)(9 87 6)))))
apply-macro(backquote((\`((一个二三)(十(\,x)十二)))((七八十九))((四五六 (2 4 6)(9 87 6))))
eval-region(648 678 t#[257\300\242b\210\301\207[(678)(apply -macro(quote backquote)parts)] 2\\\
\\\
(fn IGNORE)]);读缓冲位置651
eval-defun-2()
#[257\211\203
Backquote有趣的事情在Emacs lisp中,从读取准引用列表中返回的值是以下结构的列表:
ELISP>(defvar x(car(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)
((发现项目(成员项目seq)))
(当找到项目
(setf(car found-item)new-item))
seq))
ELISP>(replace-item'(\, x)'z(cadr x))
(1 2 z)
常见的Lisp使用逗号字符进行异常处理,在阅读相同的列表之后,X
成为 SB-IMPL :: COMMA
(SBCL):它既不是一个符号,也不是一对。
PPS。不知何故,这些准引号和逗号由读者评估者特别处理,以至于组合(eval(read< ...>))
不产生与内部评估者相同的结果。
某些工作原理
使用后缀和逗号我发现以下的作品虽然相当有点骇人听闻。
首先,不要回头引用你的结构:它不会有任何伤害,但它也不会引入任何东西。只要有(ab,c)
。
当你阅读它(或者用$ code> read 从文件或 read-from-string
),它将转换为:
elisp的> (setq x(car(from-string(ab,c))))
/ pre>
(ab
(\,c))
现在,这段魔法:有宏
backquote
做代替,但它接受结构:它不评估其参数,因此要使其在x
上执行以下操作:ELISP> (((c 10))(eval`(backquote,x)))
(ab 10)
正如您所见,
(\,c)
被替换为c
的本地绑定。
PPPS。人们会期望从字符串
(ab,c)
读取将产生
(backquote(ab,c)) `但是没有。
我希望这能提供答案。
I would like to take a large list (think faces in an emacs theme) and break it up into smaller lists in separate files. The problem I have is applying
(backquote)
to the lists once I've read them in.Here is the code I have been using to experiment with solutions:
(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
This code relies on "data" files in a subdirectory called
parts/
. Here are some samples:
parts/one.part
`( ("one" "two" "three") ("ten" ,x "twelve") )
NOTE: the,x
in this one. I want to have this evaluated after the expression is read from the file.parts/two.part
( ("four" "five" "six") (2 4 6) (9 87 6) )parts/three.part
(("seven" "eight" "nine"))Reading the "part" files is no problem. The
(defvar parts (mapcar ... )
expression works.The problem is that once I have the lists in the
parts
var, I cannot find a way to get the,x
evaluated as it would be if the whole list was backquoted and not read from files.I have tried a solution suggested in this question. You can see the
apply-macro
function commented out in my code above. When I run it I get: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
解决方案Backquote does interesting things. In Emacs lisp the returned value from reading a quasi-quoted list is a list of the following structure:
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
So, if you intend on using quasi-quoted lists, you might need to perform the replacement your self. For example, you can do:
(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 does something weird with comma characters, after reading the same list
,X
becomes an object of typeSB-IMPL::COMMA
(in SBCL): it's neither a symbol, nor a pair.PPS. Somehow those quasi-quotes and commas are treated specially by the reader-evaluator, to the point that the combo
(eval (read <...>))
does not produce the same result as internal evaluator.Something that works
While playing around with back-quotes and commas, I found that the following works, although it's quite a bit of hack.
First, don't back-quote your structures: it doesn't do any harm, but it wouldn't introduce anything either. Just have
(a b ,c)
.When you read it (either with
read
from file or withread-from-string
), it will be transformed into:ELISP> (setq x (car (read-from-string "(a b ,c)"))) (a b (\, c))
Now, the piece of magic: there is macro
backquote
that does the substitution, but it accepts a structure: it does not evaluate its argument, so to make it act onx
have to do the following:ELISP> (let ((c 10)) (eval `(backquote ,x))) (a b 10)
As you can see
(\, c)
was replaced by local binding ofc
as wanted.PPPS. One would expect that reading from string
"
(a b ,c)"would produce
(backquote (a b ,c))` but it doesn't.I hope this provides the answer.
这篇关于在elisp中,如何对从文件读取的列表应用反引号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!