使用lisp宏生成多个语句代码

时间:2011-10-17 19:29:56

标签: macros lisp

根据我的理解,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。

1 个答案:

答案 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))