我有:
(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)))
显然,这会出错,因为'符号不是连接的有效输出类型.
我确信这是我对宏如何工作的一些基本误解,并且有一种简单的方法可以做到这一点.我错过了什么?
将它们连接成一个字符串,然后从该字符串创建一个符号.
(defmacro test (a b c) (intern (concatenate 'string a b c)))
INTERN
将在当前包中实习该字符串,您还可以使用它MAKE-SYMBOL
来创建一个未处理的符号.
关于宏及其实现的困惑
我确信这是我对宏如何工作的一些基本误解
是:
宏和创建"单词"是完全独立的,正交的概念.
Lisp中不存在'word'的概念.但有符号,字符串,数字,......
如果你想到APPLEBANANACUBA
那么你可能意味着一个符号.
解决问题
首先解决如何从符号列表中创建符号的问题
实现宏
如果要创建符号串联的新符号,则需要:
获取符号,将其名称作为字符串
创建一个字符串,这是这些名称的串联
从该字符串创建一个符号,可能在一个包中.
内爆操作
我们将此操作称为implode,这是它的历史名称:
(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
原子,爆炸和爆炸
符号是原子.这意味着它们不是缺陷单元,它是链表的基本构建块.
你可以爆炸和内爆原子,这里是一个符号.
内爆符号FOO
和BAR
- >FOOBAR
爆炸的符号FOOBAR
- > F
,O
,O
,B
,A
,R