对于clojure来说非常新,所以可能是一个noob问题,但在这里。所以我读到->
宏将按顺序调用函数,我理解它是如何工作的。
(-> (+ 1 2) (* 10))
导致30
但为什么不这样做呢?
(defn testing-> [a b]
(list a b)
first)
当调用first
时,返回函数(testing-> "a" "b")
而不是“a”。我在这里错过了什么?以错误的方式使用它?
答案 0 :(得分:5)
->
需要位于函数体内。对于以 - >结尾的函数来说,这不是魔术但实际上是一个名为->
的宏,它接受一系列事情要做,并生成一个新的表达式,其中相同的东西嵌套在下一个内部:
(defn testing [a b]
(-> [a b]
list
first))
在这个例子中,当 - >宏运行它会产生一个新的表达式,如下所示:
(defn testing [a b]
(first (list [a b])))
再举一个例子,当您使用arguemnts ->
调用(+ 1 2) (* 10)
时,它会返回表达式(* (+ 1 2) 30)
,然后将其作为正常的Clojure代码进行评估。
PS:宏是一个函数,它接受Clojure表达式并产生另一个Clojure表达式。这些运行在编译周期的中间,你可以看到他们使用macroexpand-1
函数做了什么。
答案 1 :(得分:3)
宏是在编译之前重构其输入的东西。
user> (macroexpand '(-> (+ 1 2) (* 10)))
(* (+ 1 2) 10)
testing->
是一个函数,而不是宏,因此它不会重构输入。您需要在评估之前重新排列输入表单,以获得类似于->
的行为。每个有效的表单都需要在编译时转换为标准的clojure语法,这是通过reader-expansion和macro-expansion完成的。
宏构造使用标准的Clojure函数,但语义有些独特(宏应该返回将在运行时使用的表单)。您可以使用clojure.repl/source
宏来查看各种宏的实现方式。
您需要的任何操作都可以表示为函数,除非您需要新语法,否则应避免使用常规创建宏。