为什么compojure路由被定义为宏?

时间:2017-06-21 18:48:18

标签: clojure compojure compojure-api

例如Luminus网站states

  

Compojure路由定义只是接受请求的函数   地图和返回响应地图...

(GET "/" [] "Show something")
...

但是,组合路线功能

(defmacro GET "Generate a `GET` route."
  [path args & body]
  (compile-route :get path args body))

可以使用返回函数的函数make-route,但不允许进行解构。因此,作为一个函数,你不能使用compojure的特殊语法来破坏(即向量),但这是否会阻止任何形式的解构?宏给它们提高了性能吗?

(make-route :get "/some_path" some_handler)

无法使用宏包装器将破坏语法传递给函数吗?

1 个答案:

答案 0 :(得分:7)

使用宏的一个原因是用户可以编写函数和符号名称而无需引用所有内容。举个例子from the Clojure Cookbook

; Routing
(defroutes main-routes
  (GET "/"    [] (index))
  (GET "/en/" [] (index))
  (GET "/fr/" [] (index-fr))
  (GET "/:greeting/" [greeting] (view greeting)))

如果index*是函数,则必须引用所有view符号以及greetingGET

; Routing
(defroutes main-routes
  (GET "/"    [] '(index))
  (GET "/en/" [] '(index))
  (GET "/fr/" [] '(index-fr))
  (GET "/:greeting/" '[greeting] '(view greeting)))

由于在调用函数之前计算函数参数,因此只要读取表单就会评估(index) 。此外,greeting arg将在每个HTTP请求上进行更改,因此显然不会提前知道。

宏还会处理所有解构魔法,这些魔法通常不会通常用于常规功能。

经常令人困惑的事情(并没有很好地向初学者解释)就是这样一条线:

(GET "/:greeting/" [greeting] (view greeting))

不正常" Clojure代码" 。相反,它是一种简写(特定于域的语言或DSL),GET宏将摄取并用作如何生成" legal" Clojure代码。 DSL通常更短,更简单,并且对于人来说比最终生成的代码更方便,就像Clojure更短,更简单,和比Clojure编译器生成的Java字节码更方便,或者最终由JVM生成的机器汇编语言代码。

简而言之,每个宏都是"预编译器"将DSL转换为普通的Clojure,然后由Clojure编译器提取以生成Java字节码。

话虽如此, 可以 重新安排将所有宏魔法放入defroutes宏,以便GET symbol既不是函数也不是宏,而只是一种标记,如实现中的:get关键字。作为用户,这些实施细节通常并不重要。

<强>更新

最好只在功能不起作用或非常笨拙的情况下使用宏。决定因素通常是如果想要使用裸(未引用)符号,而不是事先评估它们。 Core Clojure本身对许多构造使用宏,这些构造是内置的&#34;在其他语言中,包括defnforandorwhen和其他语言。

另请注意,宏不能执行某些功能,例如作为filter等高阶函数的参数。

总之,一个函数定义了 行为 。宏定义 语言扩展