Как мне написать этот макрос в clojure?

У меня есть эта функция:

(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, добро, зло, нейтраль)

вместо:

Но я застрял. Мой лучший снимок выглядит так:

(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 там.

Это выглядело многообещающе, пока я не заметил, что это произвело новый генсим:

(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 ответа

Решение

Я думаю, что вы можете избежать здесь вообще. Я не понимаю, как можно "загрязнить" окружающую среду, не используя 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>" )))))

Проблема с вашим макрокодом состоит в том, что динамический символ, который является частью квазицитирования, не может использоваться вне заключенной в кавычки части, т. Е. В коде разделения / удаления кавычек. Однако возможен другой способ, то есть вы делаете gensym в части выполнения макроса и используете ее внутри части квазицитирования, как показано ниже:

(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>")))))) 
Другие вопросы по тегам