如何在clojure中编写这个宏?

时间:2013-01-31 12:39:09

标签: macros clojure ring gensym

我有这个功能:

(defn handler [request]
  (case (request :uri)
    "/" (home request)
    "/good" (good request)
    "/evil" (evil request)
    "/neutral" (neutral request)
    (status-response 404 (str "<h1>404 Not Found: " (:uri request) "</h1>" ))))

但我不断更改页面列表 - 解析为同名的函数,我希望能够写出来:

(def-handler good evil neutral)

代替:

但我被困住了。到目前为止,我最好的镜头看起来像:

(defmacro def-handler [& addresses]
  `(defn handler [request#]
     (case (request# :uri)
       ~@(mapcat (fn[x] [(str "/" x) (list x 'request)]) addresses)
       "/" (home request#)
       (status-response 404 (str "<h1>404 Not Found: " (:uri request#) "</h1>" )))))

但它不太有用,因为生成的调用中的请求不是gensym,我不知道如何在那里获得gensym。

这看起来很有希望,直到我注意到它成了一个新的gensym:

(defmacro def-handler [& addresses]
  `(defn handler [request#]
     (case (request# :uri)
       ~@(mapcat (fn[x] [(str "/" x) `( ~x request#)]) addresses)
       "/" (home request#)
       (status-response 404 (str "<h1>404 Not Found: " (:uri request#) "</h1>" )))))

2 个答案:

答案 0 :(得分:3)

我认为你可以在这里避免使用gensym。我不知道你怎么能污染&#34;不使用gensym的环境。没有gensym的例子:

(defmacro def-handler [& addresses]
  `(defn handler [~'request]
     (case (~'request :uri)
       ~@(mapcat (fn[x] [(str "/" x) (list x 'request)]) addresses)
       "/" (home ~'request)
       (status-response 404 (str "<h1>404 Not Found: " (:uri ~'request) "</h1>" )))))

答案 1 :(得分:1)

宏代码的问题在于,作为quasiquoting一部分的动态符号不能在引用部分之外使用,即在unquote / unquote-splicing代码中。但是另一种方式是可能的,那就是你在宏执行部分做gensym并在quasiquoting部分中使用它,如下所示:

(defmacro def-handler [& addresses]                                                                                                                  
  (let [request (gensym)]                                                                                                                            
  `(defn handler [~request]                                                                                                                          
     (case (~request :uri)                                                                                                                           
       ~@(mapcat (ƒ [x] [(str "/" x) (list x request)]) addresses)                                                                                   
       "/" (home ~request)                                                                                                                           
       (status-response 404 (str "<h1>404 Not Found: " (:uri ~request) "</h1>"))))))