【问题标题】:Macros in Clojure, evaluation and quotingClojure 中的宏,评估和引用
【发布时间】:2015-04-01 19:30:23
【问题描述】:

我正在尝试编写一个宏,以便仅在某些环境中有条件地将 compojure 处理程序包装在中间件中。我似乎迷失了评估顺序以及我应该引用什么/如何引用。我目前的尝试如下:

(defn empty-middleware [handler]
  (fn [request] (handler request)))

(defmacro prod [handler middleware]
  (if (= "production" (System/getenv "APP_ENV"))
    (middleware handler)
    (empty-middleware handler)))

期望的用法是:

(in/prod (fn [handler]  (airbrake/wrap-airbrake handler config/airbrake-api-key)))

--- 编辑 ---

更多信息: in/prod 应该在线程宏内部使用,该宏将路由包装在许多中间件中,例如:

(-> handler
    middleware1
    middleware2
    (in/prod (middleware3 middleware-3-param1))

middleware3 和 in/prod 都需要 handler 作为参数。在括号中包装 middleware3 评估不可能将处理程序作为参数传递。因此,我认为需要一个宏。我想出了如何制作/生产一个将中间件3和中间件参数作为参数传递的函数:

(defn prod [handler middleware & middleware-params]
  (if (= "production" (System/getenv "APP_ENV"))
    (apply middleware handler middleware-params)
    handler))

虽然它稍微改变了语法。调用看起来像:

(-> handler
    middleware1
    middleware2
    (in/prod middleware3 middleware-3-param1)

如何才能使用如下语法:

(in/prod (middleware3 middleware-3-param1)

【问题讨论】:

  • 我看不出有什么理由在这里使用宏。您能否提供更多详细信息,说明为什么这必须是宏而不是返回处理程序的 fn
  • 好吧,也许不是。最初我的想法是我需要宏而不是评估中间件。那是在我将它包装在函数中之前。理想情况下,我希望能够不将“airbrake/wrap-airbrake”包装在函数中,也就是样板更少。
  • 希望的用法不是更像:(in/prod (airbrake/wrap-airbrake handler config/airbrake-api-key))?根据您的使用,您可以简单地使用一个函数。而prod 需要两个参数,而你只传递了一个,这是错字吗?

标签: macros clojure lisp compojure


【解决方案1】:

如果您希望应用的中间件也是一个宏,那么您可能需要将它作为一个宏,因此您正遭受宏传染的困扰。在这种情况下,您只需要一个宏,它返回两个可能的 s-expressin 之一以包含在结果代码中。一种是直接调用处理程序,另一种是包装在给定的中间件中。

(defmacro prod [handler middleware]
  (if (= "production" (System/getenv "APP_ENV"))
    `(~middleware ~handler) ;; or (list middleware handler)
     handler))

如果您目前没有遭受宏传染,但无法通过在其他地方删除宏来解决此问题,那么您不需要使用这样的宏,并且您示例中的代码可以简单地用作函数而不是用作一个宏。在这两种情况下都不需要空中间件位。

【讨论】:

  • 确实empty-middleware的实现只是identity的一个更严格的版本。
猜你喜欢
  • 2012-11-19
  • 1970-01-01
  • 1970-01-01
  • 2011-10-21
  • 1970-01-01
  • 1970-01-01
  • 2011-07-12
  • 2015-05-25
  • 1970-01-01
相关资源
最近更新 更多