我们可以定义和使用这样的匿名函数:
repl=> (#(+ 10 %) 1)
11
但是->
宏不会接受这样的匿名函数。假设我想添加10然后乘以2.我试着写:
(-> 5 #(+ 10 %) #(* 2 %))
但由于某种原因,这不是正确的代码,正确的代码是
(-> 5 (+ 10) (* 2))
(+ 10)
和#(+ 10 %)
之间的区别是什么,为什么赢得->
宏接受使用#()
定义的匿名函数?
答案 0 :(得分:5)
这是我尝试解释的。分为两部分。
首先,匿名文字语法。当您编写#(+ 10 %)
时,它会扩展为功能类似于以下内容的内容:
(fn [x] (+ 10 x))
对于前。
=> (macroexpand '(#(+ 10 %))
会返回类似的内容:
(fn* [p1__7230#] (+ 10 p1__7230#))
第二部分。当您使用线程宏时,作为docs say,宏会通过将第一个参数作为第二个项插入到第一个表单中来扩展。如果有更多表单,请将第一个表单作为第二个表单中的第二个项目插入,依此类推。
这里的关键术语是第二项。它并不关心你提供什么形式的参数,它只会使用该规则进行扩展。
所以,当你使用
时,要结合两个点(-> 5 #(+ 10 %) #(* 2 %))
遵循规则,它会扩展为与此
功能相似的东西(fn (fn 5 [x] (+ 10 x)) [y] (* 2 y))
不编译。
另外,作为旁注,表单(+ 10)
不是匿名函数。它是一个部分函数调用,在宏扩展期间使用参数进行更新。而'部分',我的意思是在字面意义上,而不是在函数编程意义上。
更新
要解释为什么它将括号中的匿名文字括起来(作为对问题的评论),您可以推断出这两个规则的结果。对于前。
=> (macroexpand '(#(+ 10 %)))
将导致功能等同于
((fn [x] (+ 10 x)))
因此,当一个项目插入其第二个位置时,它看起来像
((fn [x] (+ 10 x)) 5)
相当于
(#(+ 10 %) 5)