为什么匿名函数定义语法不同?

时间:2015-09-29 06:01:49

标签: clojure anonymous-function function-composition

我们可以定义和使用这样的匿名函数:

repl=> (#(+ 10 %) 1)
11

但是->宏不会接受这样的匿名函数。假设我想添加10然后乘以2.我试着写:

(-> 5 #(+ 10 %) #(* 2 %))

但由于某种原因,这不是正确的代码,正确的代码是

(-> 5 (+ 10) (* 2))

(+ 10)#(+ 10 %)之间的区别是什么,为什么赢得->宏接受使用#()定义的匿名函数?

1 个答案:

答案 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)