在elisp中,如何对从文件读取的列表应用反引号 [英] In elisp, how do I apply backquote to lists read from files

查看:167
本文介绍了在elisp中,如何对从文件读取的列表应用反引号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要一个大的列表(在emacs主题中考虑面孔),并将其分解成单独文件中的较小列表。我已经读了这个问题,我正在将(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 / 的子目录中的数据文件。以下是一些示例:


  1. parts / one.part

    `((onetwothree)(ten,x12))

    注意:,x 在这一个。我想在表达式从文件中读取后进行评估。

  2. parts / two.part

    ((fourfivesix)(2 4 6)(9 87 6))

  3. 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))))
(ab
(\,c))
/ pre>

现在,这段魔法:有宏 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:

  1. 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.
  2. parts/two.part
    ( ("four" "five" "six") (2 4 6) (9 87 6) )
  3. 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 type SB-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 with read-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 on x 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 of c 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆