2017-01-17 26 views
0

我:如何在Common Lisp的宏参数中创建一个单词?

(defmacro test (a b c) 
    `'(,a ,b ,c)) 

运行(test apple banana cuba)(APPLE BANANA CUBA)预期。

如何使宏产生APPLEBANANACUBA?

我想:

(defmacro test (a b c) 
     `'(,a,b,c)) 

但运行(test ant bites chris)仍返回(ANT BITES CHRIS)作为三个独立的ARGS列表。

我试过变化,似乎没有工作。像这样:

(defmacro test (a b c) 
    `(apply #'concatenate 'symbol '(,a ,b ,c))) 

很明显,这个错误出来了,因为符号不是一个有效的连接输出类型。

我确定这是我对宏如何工作的一些基本误解,并且有一个简单的方法可以做到这一点。我错过了什么?

+0

@JoshuaTaylor即使其他问题包括信息是这个问题的答案,它嵌入在问题和答案中的许多其他信息中。你可以在这个问题的评论中加入一个链接,指出那里有'更多'的信息,但将这两个问题称为'相同'(这是重复的意思)对任何可能从快速清晰解决方案中受益的人来说都是一种伤害未来。真的很高兴,但请重新考虑。 –

回答

6

将它们连接成一个字符串,然后从该字符串中创建一个符号。

(defmacro test (a b c) 
    (intern (concatenate 'string a b c))) 

INTERN意志实习生在当前包串,你也可以使用MAKE-SYMBOL创建uninterned符号。

5

混淆宏及其实施

我相信这是我的一部分了一些基本的误解有关宏是如何工作的

是:

  • 宏和创造'词'是完全独立的,正交的概念。

  • 'word'的概念在Lisp中不存在。但有符号,字符串,数字,...

  • 如果你认为那么你可能意味着符号

解决问题

  1. 首先解决的问题是如何从符号列表创建符号
  2. 落实宏观

如果你想创建一个新的符号是符号的连接,那么你需要:

  1. 得到符号,把他们的名字作为字符串
  2. 创建一个字符串,这些名字
  3. 的串联,从这个字符串创建一个符号,可能是在一个包。

破灭操作

让我们把这种操作破灭,这是它的历史名称:

(defun implode-symbols (symbols &optional (package *package*)) 
    (when symbols 
    (values 
    (intern (with-output-to-string (stream) 
       (dolist (symbol symbols) 
       (write-string (symbol-name symbol) stream))) 
      package)))) 


CL-USER 30 > (implode-symbols '(a - b - c - foo - bar)) 
A-B-C-FOO-BAR 

现在,人们可以做出更一般的版本,它可以内爆全部东西:

(defun implode (things) 
    (when things 
    (values 
    (intern (with-output-to-string (stream) 
       (dolist (thing things) 
       (princ thing stream))))))) 

CL-USER 31 > (implode '(a - b - c - foo :bar - 42 - "BAZ")) 
A-B-C-FOOBAR-42-BAZ 

宏爆一些参数

鉴于我们从一个事物的列表中创建一个符号的功能,我们可以轻松编写宏:

CL-USER 37 > (defmacro test (a b c) 
       `',(implode (list a b c))) 
TEST 

CL-USER 38 > (macroexpand-1 '(test foo bar baz)) 
(QUOTE FOOBARBAZ) 
T 

CL-USER 39 > (test foo bar baz) 
FOOBARBAZ 

原子内爆和爆炸

符号是原子。这意味着它们不是cons cell,它是链接列表的基本构建块。

你可以爆炸并爆炸一个原子,这里是一个符号。

  • 破灭符号FOOBAR - >FOOBAR
  • 爆炸符号FOOBAR - >FOOBAR
+0

这是一个很好的说明。谢谢。那么传递给宏的文本是什么?也就是说,我可以打电话(测试foo bar baz)而不必引用args作为'foo'bar'baz。但是如果测试是一个函数而不是宏,(测试foo酒吧baz)将寻找变量foo酒吧baz。什么是通向宏的东西?一个原子?一个符号?或者是其他东西?好像它只是文字... –

+1

@λ-:为什么不试试呢?询问宏A,B和C的值是什么。 DESCRIBE是你的朋友。 Lisp宏与* text *无关。这都是数据。 –