2014-01-06 28 views
0

我编写了一个如下所示的宏,它按预期工作以记录在运行时传递给函数的参数。宏在多个语法引用形式中重用auto-gensym

(use 'robert.hooke) 

(defmacro log-func-args [func arg-log-option print-suffix] 
    (condp = arg-log-option 
    :all `(add-hook (var ~func) (fn [f# & args#] 
            (println "****** " (:name (meta (var ~func))) " called with " 
             ~print-suffix args#) 
            (apply f# args#))) 

    :first `(add-hook (var ~func) (fn [f# & args#] 
            (println "****** " (:name (meta (var ~func))) " called with " 
             ~print-suffix (first args#)) 
            (apply f# args#))) 

    :rest `(add-hook (var ~func) (fn [f# & args#] 
            (println "****** " (:name (meta (var ~func))) " called with " 
             ~print-suffix (rest args#)) 
            (apply f# args#))) 
    ) ) 

这随后被用于像这样:

(log-func-args my-func-name :rest "[server,buyer]: ") 

上面的宏显得有点冗长,所以我试图重构它,以便代替多个点对点的,我只有一个与condp卷起里面,像这样:

(defmacro log-func-args [func arg-log-option print-suffix] 
`(add-hook (var ~func) (fn [f# & args#] 
         ~(condp = arg-log-option 
          :all `(println "****** " (:name (meta (var ~func))) " called with " 
             ~print-suffix args#) 
          :first `(println "****** " (:name (meta (var ~func))) " called with " 
              ~print-suffix (first args#)) 
          :rest `(println "****** " (:name (meta (var ~func))) " called with " 
             ~print-suffix (rest args#))        
         ) 

         (apply f# args#) )) 

这给了我一个RuntimeException抱怨在的println ARGS#不能得到解决(因为ARGS#两个语法援引形式生成的符号 - add-hook表单和println表单 - 不一样)。什么是干净的补救措施?

回答

0

找到一个解决方案(礼貌编程Clojure书)使用gensym func与let。这允许两个语法引用的表单共享相同的参数符号。希望这可以帮助别人。很想看到任何其他解决方案。

(defmacro log-func-args2 [func arg-log-option print-suffix] 
    (let [args (gensym "args")] 
    `(add-hook (var ~func) (fn [f# & ~args] 
           ~(condp = arg-log-option 
           :all `(println "****** " (:name (meta (var ~func))) " called with " 
               ~print-suffix ~args) 
           :first `(println "****** " (:name (meta (var ~func))) " called with " 
               ~print-suffix (first ~args)) 
           :rest `(println "****** " (:name (meta (var ~func))) " called with " 
               ~print-suffix (rest ~args))) 

           (apply f# ~args) ))) ) 
0

看看potemkin的unify-gensyms函数。它允许您使用两个散列(##)而不是一个来表示应该用相同的生成符号替换的值。

跨越多种形式的越多,解决方案越好(与明确的let/gensym之一相比)。