将函数映射传递给宏

时间:2011-04-28 02:53:58

标签: clojure

我有一个宏,它将实现一个作为监听器的Java接口。我定义了宏来获取包含我想要解构的函数的映射,并用于每个接口方法。这是宏: -

(defmacro with-cache-listener-m [component event body]
   (let [{:keys [f-insert f-update]} body]
     `(. ~component addMapListener
     (proxy [AbstractMapListener] []
       (entryInserted [~event] ~f-insert ~event)
       (entryUpdated [~event] ~f-update ~event)))))

身体地图是这样的: -

(def m-callbacks {:f-insert callback-insert :f-update callback-update})

但是当我致电(macroexpand '(with-cache-listener-m test-cache e m-callbacks))时,它会扩展为(. test-cache user/addMapListener (clojure.core/proxy [com.tangosol.util.AbstractMapListener] [] (user/entryInserted [e] nil e) (user/entryUpdated [e] nil e)))

回调函数为零。我是否需要以不同的方式定义它们,或者我是否采取了错误的方式。

2 个答案:

答案 0 :(得分:4)

当您调用with-cache-listener-m宏时,body参数作为符号绑定到'm-callbacks,因此当您尝试对该局部变量进行解构时,它将无效,因为它是ain不是地图。您可以让生成的表单完成这样的工作:

(defmacro with-cache-listener-m [component event body]
  `(let [{:keys [f-insert# f-update#]} ~body]
     (. ~component addMapListener
        (proxy [AbstractMapListener] []
          (entryInserted [~event] f-insert# ~event)
          (entryUpdated [~event] f-update# ~event)))))

但最后我不确定你的代码是否需要宏,你是否尝试将其编写为函数:

(defn add-map-listener [component insert-fn update-fn]
  (.addMapListener component
    (proxy [AbstractMapListener] []
      (entryInserted [e] (insert-fn e))
      (entryUpdated [e] (update-fn e)))))

如你所见,我改变了一些事情:

  • 使函数名称更清晰,您的宏与其他通常在某种特殊上下文中评估某些代码(body)的with- *宏不同。
  • 删除了事件参数,因为它似乎没有任何用处。
  • 使insert-fn和update-fn参数显式化以简化示例。
  • 使用新方法调用语法。
  • 修复了代理实际使用给定函数的方法。

如果您想让这些功能完全可选,并且可以按任何顺序给出,您可以随时使用:

(defn add-map-listener [component & functions]
  (let [{:keys [insert-fn update-fn]} (into {} functions)]
    (when-not (empty? functions)
      (.addMapListener component 
        (proxy [AbstractMapListener] []
          (entryInserted [e] (insert-fn e))
          (entryUpdated [e] (update-fn e)))))))

请注意,我没有在没有给出函数的情况下添加代码来调用addMapListener。

答案 1 :(得分:1)

宏不是函数:它们只知道在编译时传递给它们的文字形式。如果您为变量x指定一个值(例如10),然后将x传递给您的宏,则会看到不是10 x。如果代替def m-callbacks然后传递该符号,那么您的宏可能会正常工作,您只需将地图直接作为文字传递。