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

beo*_*ver 6 clojure compojure compojure-api

例如,Luminus网站说明了这一点

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

(GET "/" [] "Show something")
...
Run Code Online (Sandbox Code Playgroud)

但是组合路线不是功能

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

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

(make-route :get "/some_path" some_handler)
Run Code Online (Sandbox Code Playgroud)

难道不能使用宏包装器将破坏语法传递给函数吗?

Ala*_*son 7

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

; Routing
(defroutes main-routes
  (GET "/"    [] (index))
  (GET "/en/" [] (index))
  (GET "/fr/" [] (index-fr))
  (GET "/:greeting/" [greeting] (view greeting)))
Run Code Online (Sandbox Code Playgroud)

如果是函数index*,所有符号加上viewgreeting必须引用GET:

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

由于被调用函数之前函数参数进行评估,(index) 等人将尽快作为表单读取评价.此外,greetingarg将在每个HTTP请求上进行更改,因此显然不会提前知道.

宏也会处理所有的解构魔法,这些魔法通常不能通过常规函数实现.

经常令人困惑的事情(并没有很好地解释为初学者)是一条线,如:

(GET "/:greeting/" [greeting] (view greeting))
Run Code Online (Sandbox Code Playgroud)

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

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

话虽如此,它可以重新安排将所有的宏魔法放入defroutes宏中,这样GET符号既不是函数也不是宏,而只是一种类型的标记,就像实现中的:get关键字一样.作为用户,这些类型的实现细节通常无关紧要.

更新

最好只在函数不起作用或非常笨拙时才使用宏.决定因素通常是如果想要使用裸(未引用)符号,而不是事先评估它们.核心Clojure的本身使用了许多结构是"内建"在其他语言中的宏,包括defn,for,and,or,when,和其他人.

还要注意一个宏不能做一些函数可以做的事情,比如作为高阶函数的参数就好了filter.

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