【问题标题】:How to create a single word from macro arguments in Common Lisp? [duplicate]如何从 Common Lisp 中的宏参数创建一个单词? [复制]
【发布时间】:2017-01-17 05:00:11
【问题描述】:

我有:

(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) 作为三个单独参数的列表。

我尝试了各种变化,但似乎都没有。喜欢这个:

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

显然,这会出错,因为 'symbol 不是连接的有效输出类型。

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

【问题讨论】:

  • @JoshuaTaylor 尽管其他问题包含作为该问题答案的信息,但它包含在问题和答案中的许多其他信息中。您可以在该问题的评论中添加一个链接,说明那里有“更多”信息,但是将这两个问题称为“相同”(这是重复的意思)对任何可能从快速清晰的解决方案中受益的人都是一种伤害未来。真的由你决定,但请重新考虑。

标签: macros common-lisp


【解决方案1】:

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

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

INTERN 将实习生当前包中的字符串,您也可以使用MAKE-SYMBOL 创建一个非实习符号。

【讨论】:

    【解决方案2】:

    对宏及其实现的困惑

    我确信这是我对宏如何工作的一些基本误解

    是的:

    • 宏和创建“词”是完全独立的正交概念。

    • Lisp 中不存在“单词”的概念。但是有符号、字符串、数字……

    • 如果您想到APPLEBANANACUBA,那么您可能指的是一个符号

    解决问题

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

    如果你想创建一个新的符号,它是符号的串联,那么你需要:

    1. 获取符号,将它们的名称作为字符串
    2. 创建一个字符串,将这些名称串联起来
    3. 从该字符串创建一个符号,可能在一个包中。

    内爆操作

    我们称这个操作为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
    

    原子,内爆和爆炸

    符号是原子。这意味着它们不是 cons 单元,后者是链表的基本构建块。

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

    • 内爆符号FOOBAR -> FOOBAR
    • 分解符号FOOBAR -> F, O, O, B, A, R

    【讨论】:

    • 这是一个很好的说明。谢谢。那么传递给宏的文本是什么?也就是说,我可以调用 (test foo bar baz) 而不必将 args 引用为 'foo 'bar 'baz。但是,如果 test 是一个函数而不是宏, (test foo bar baz) 将查找变量 foo bar baz。传递给宏的东西是什么?一个原子?一个符号?或者是其他东西?好像只是文字……
    • @λ-: 为什么不试试呢?问宏 A、B、C 的值是多少。描述是你的朋友。 Lisp 宏与 text 无关。都是数据。
    猜你喜欢
    • 1970-01-01
    • 2018-08-21
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-06
    • 2016-10-27
    • 2012-07-30
    相关资源
    最近更新 更多