【问题标题】:How to write a nested macro that prints its own suffix?如何编写一个打印自己后缀的嵌套宏?
【发布时间】:2012-09-24 21:39:04
【问题描述】:

我正在努力更好地理解listing 13.3 in The Joy of Clojure。它是一个生成其他宏的宏(很像 Clojure 1.4 中原始数组函数的实现方式)。

我想编写一个宏,它在运行时只打印生成的宏的后缀。即

user=> (nested-macro joe)
user=> (nested-macro-named-joe)
hello from joe
nil

我无法完成这项工作。

这是我尝试过的:

尝试 1

(defmacro nested-macro [name]
  `(defmacro ~(symbol (str "nested-macro-named-" name))
     []
     `(println "hello from " ~name)))

输出:

hello from #<core$name clojure.core$name@502c06b2>

尝试 2

(defmacro nested-macro [name]
  (let [local-name name]
    `(defmacro ~(symbol (str "my-custom-macro-named-" ~local-name))
       []
       `(println "hello from " ~local-name))))

错误

IllegalStateException Attempting to call unbound fn: #'clojure.core/unquote clojure.lang.Var$Unbound.throwArity (Var.java:43)

尝试 3:

(defmacro nested-macro [name]
  (let [local-name name]
    `(defmacro ~(symbol (str "nested-macro-named-" name))
       []
       `(println "hello from " ~(symbol local-name)))))

编译器错误:

CompilerException java.lang.RuntimeException: No such var: joy.dsl/local-name

只是为了它,我还尝试将 # 添加到局部变量中,结果与上面类似,但使用“自动”名称,例如 local-name__1127__auto__ 我不认为这是一部分然而,解决方案。

我怎样才能做到这一点?

【问题讨论】:

    标签: clojure macros


    【解决方案1】:

    要知道宏出了什么问题,我总是使用macroexpand-1

    从你的第一个例子:

    (macroexpand-1 '(nested-macro joe))
    

    结果:

    (clojure.core/defmacro nested-macro-named-joe [] 
      (clojure.core/seq 
        (clojure.core/concat 
          (clojure.core/list (quote clojure.core/println)) 
          (clojure.core/list "hello from ") 
          (clojure.core/list clojure.core/name))))
    

    如果您查看最后一个参数,则表明您正在使用 clojure.core/name,这可能不是您想要的,因为您实际上想要名为“name”的参数。

    要修复它,只需在 name 参数中添加另一个取消引号,但由于名称参数实际上是一个符号,您真正想要的是获取它的名称,如下所示:

    (defmacro nested-macro [the-name]
      `(defmacro ~(symbol (str "nested-macro-named-" the-name))
         []
         `(println "hello from " ~~(name the-name))))
    

    【讨论】:

    • '~~name 是在类似情况下引用的更通用解决方案 - 您并不总是乐于获得值的字符串表示形式。
    • 将 ~~(name the-name) 替换为 '~~name 会产生 CompilerException java.lang.RuntimeException: Unable to resolve symbol: joe in this context, compiling:(NO_SOURCE_PATH:1)
    • 呃,嵌套引用很难。我猜是'~'~name 阻止内部宏尝试解析名称。
    • 谢谢,我想我现在理解了嵌套引用。接下来:&env&form
    猜你喜欢
    • 1970-01-01
    • 2019-02-22
    • 2022-11-25
    • 1970-01-01
    • 2021-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多