根据我的理解,LISP中宏的一个用法是生成所需的代码。
我有以下主体代码:
(list (list "aVar" "Hi")
(list "bVar" 10)
(list "addSW1" (equal dpl->addSW1))
...
(list "addSW100" (equal dpl->addSW100)))
所以,基本上我正在尝试编写为SW1
生成代码到SW100
的宏,这样我就不需要写100行。
我创建了我的第一个宏:
(defmacro myMac1 (dpl sw)
`(list ,switchStr "boolean" (equal "Y" (get ,dpl ,sw))))
这对我有用,所以我现在可以(myMac1 "addSW1")
生成单个列表语句。
然后,我创建了第二个mac:
(defmacro myMac2 (dpl @rest allSwitches)
`(mapcar (lambda (sw)
(myMac1 ,dpl sw))
,@allSwitches))
所以,如果我写(myMac2 dpl "addSW1" "addSW2" ... "addSW100")
它将生成:
(list (list "addSW1" (equal dpl->addSW1))
... till 100))
但是,在主体代码中我不想要列表的列表。我只想要100个清单。
任何解决方案?很抱歉很长的描述:P。
答案 0 :(得分:3)
您必须了解编译时间和评估时间之间的区别。
宏在编译时展开,引用的所有内容都按原样插入到源代码中(没有评估)。因此(macroexpand-1 '(myMac2 1 2 3))
会产生(mapcar (lambda (sw) (myMac2 1 sw)) 2 3)
(另请注意,您必须使用&rest
代替@rest
。
如果您想获取mapcar
的结果,则不应引用该表单:
(defmacro myMac2 (dpl &rest allSwitches)
(mapcar (lambda (sw)
`(myMac1 ,dpl ,sw))
allSwitches))
(macroexpand-1 '(myMac2 1 2 3)) => ((myMac1 1 2) (myMac1 1 3))
但这不是一个有效的表格。你想要的是(list (myMac1 1 2) (myMac1 1 3))
。为了达到这个目的,你必须在生成的表单周围包裹list
(为什么你应该在这里使用,@
留下来作为练习;)
(defmacro myMac2 (dpl &rest allSwitches)
`(list ,@(mapcar (lambda (sw)
`(myMac1 ,dpl ,sw))
allSwitches)))
(macroexpand-1 '(myMac2 1 2 3)) => (list (myMac1 1 2) (myMac1 1 3))