创建一个宏以返回一个reify(java接口),但在clojure中使用提供的带引号的表达式

创建一个宏以返回一个reify(java接口),但在clojure中使用提供的带引号的表达式,clojure,Clojure,我试图实现的是在宏中实现一个带有具体化的抽象类,但是应该在扩展时返回的表达式将提供给宏: (defmacro a-printable [body] `(reify Printable (print [this g# pf# page#] (if (= page# 0) (do ~body ;; the supplied part (Printable/PAGE_EXISTS)) (Printable/NO_SUCH_PAGE))) (def exp '(do

我试图实现的是在宏中实现一个带有具体化的抽象类,但是应该在扩展时返回的表达式将提供给宏:

(defmacro a-printable
[body]
`(reify Printable
 (print [this g# pf# page#]
  (if (= page# 0)
   (do
    ~body ;; the supplied part
    (Printable/PAGE_EXISTS))
   (Printable/NO_SUCH_PAGE)))

(def exp '(do (.translate g (.getImageableX pf) (.getImageableY pf))
              (.drawString g "foo" 10 10))) ;; the form to pass
(a-printable exp)
问题是,在我传递的表达式中,我想使用在宏和具体化
g#,pf#
中定义的自动生成的变量。 我尝试添加带有
(ns resolve*ns*g)
(ns resolve*ns*pf)
的引用表达式,但我不确定宏中是否正在解析该表达式。
g
java.awt.Graphics
这是一个抽象类,
pf
java.awt.print.PageFormat
,这是一个带构造函数的普通类。
有人知道如何做到这一点,或者把我引向正确的方向吗?

我相信诀窍在于,如果你不想在宏中使用带名称空间的符号,你可以在它们前面加上
~'
,例如
~'g
。然后,我对宏进行了以下其他修改:

  • 主体
    参数前面加上
    &
    前缀,使其长度可变
  • 将主体拼接到宏中
  • 删除
    (可打印/PAGE\u存在)
    (可打印/NO\u页面)
    周围的括号:这些是要返回的静态变量值,而不是函数调用 这就是固定宏的外观:

    (defmacro a-printable
      [& body]
      `(reify Printable
         (print [~'this ~'g ~'pf ~'page]
           (if (= ~'page 0)
             (do
               ~@body ;; Splice it!
               Printable/PAGE_EXISTS)
             Printable/NO_SUCH_PAGE))))
    
    这就是创建实例的方法。请注意,我不需要使用
    do
    将参数包装到宏中:

    (def p (a-printable
            (.translate g (.getImageableX pf) (.getImageableY pf))
            (.drawString g "foo" 10 10)))
    
    但是需要注意的是:我不确定引入新符号(如
    pf
    g
    )是否是一种好的做法,但我找不到提及为什么这种做法不好的参考文献。有一些方法可以实现与本问题中所问内容类似的功能,而无需借助宏。不使用宏的版本不会太长:

    (defn a-printable-fn [body-fn]
      (reify Printable
        (print [this g pf page]
          (if (= ~'page 0)
            (do
              (body-fn this g pf page)
              Printable/PAGE_EXISTS)
            Printable/NO_SUCH_PAGE))))
    
    
    (def p (a-printable-fn
            (fn [this g pf page]
              (.translate g (.getImageableX pf) (.getImageableY pf))
              (.drawString g "foo" 10 10))))
    

    首先感谢您抽出时间回答我的问题。其次,我想问,为什么我更喜欢函数版本,我想,因为我想传递引用表达式宏是我应该做的事情。这将是一个坏的做法,一般来说,使用宏时,我可以做同样的功能?