【问题标题】:Generating multiple statement code using lisp macro使用 lisp 宏生成多条语句代码
【发布时间】:2011-10-17 19:29:56
【问题描述】:

据我了解,LISP 中宏的用途之一是生成所需的代码。

我有以下主体代码:

(list (list "aVar" "Hi")
      (list "bVar" 10)
      (list "addSW1" (equal dpl->addSW1)) 
      ...
      (list "addSW100" (equal dpl->addSW100))) 

所以,基本上我正在尝试编写为SW1SW100 生成代码的宏,这样我就不需要写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。

【问题讨论】:

    标签: macros lisp


    【解决方案1】:

    您必须了解编译时间和评估时间之间的区别。

    宏在编译时展开,所有被引用的内容都按原样插入到源代码中(无需评估)。所以(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))
    

    【讨论】:

    • 感谢您的帮助。当我从列表中调用这个宏时,我想要 (myMac1 1 2) (myMac1 1 3) 作为我的最终解决方案,而不是它们的列表。给出的第二个解决方案产生两个 myMac1 的列表。是否可以只获得 (myMac1 1 2) (myMac1 1 3)。
    • 我也尝试了您的第一个解决方案,但出现错误:Error eval: not a function - (mymac1 1 2)。
    • 顺便说一下,这是方案方言。节奏技巧。
    • 这里没关系,是 Lisp 还是 Scheme。回答关于获取(myMac1 1 2) (myMac1 1 3) 的问题:1 个宏可以生成 1 个项目(原子、列表或其他对象)。从技术上讲,您无法获得 2 个项目,但您可以将它们嵌套在一个特殊的运算符中,在 Lisp 中称为 progn,在 Scheme 中称为 begin。这就是需要,@ 的地方:它接受一个列表(宏的输出)并将其“拼接”到包装形式中。但应该有一个包装形式,在你的情况下将是begin。但请注意,这样您将丢失调用list 的所有结果,但最后一个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-20
    • 2012-11-27
    • 1970-01-01
    • 2020-09-18
    • 2017-11-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多