也许这听起来很荒谬,但对我来说仍然不能完全清楚匿名函数的#
应该来的区别。例如,在此示例中,我过滤了正数的除数:
(filter #(zero? (mod 6 %)) (range 1 (inc 6))) ;;=> (1 2 3 6)
但将#
放在(mod 6 %)
之前会导致错误。是否有规则在这样的上下文中我的匿名函数开始,为什么#
应该在(zero? ...
之前?
答案 0 :(得分:7)
这表明#(...)语法只是(fn [x] ...)的缩写:
(defn divides-6 [arg]
(zero? (mod 6 arg)))
(println (filter divides-6 (range 1 10))) ; normal function
(println (filter (fn [x] (zero? (mod 6 x))) (range 1 10))) ; anonymous function
(println (filter #(zero? (mod 6 %)) (range 1 10))) ; shorthand version
;=> (1 2 3 6)
;=> (1 2 3 6)
;=> (1 2 3 6)
使用defn
只是(def divides-6 (fn [x] ...))
的简写(即def
和fn
部分合并为defn
以节省一点打字费用。如果我们只使用一次函数,我们就不需要定义全局名称divides-6
。我们可以直接定义函数内联的位置。 #(...)
语法只是一个简写版本,如示例所示。
请注意,表单#(...)
的全名是"匿名函数文字"。您可能还会看到它被称为"功能阅读器宏"或只是"功能宏"。语法(fn [x] ...)
被称为"函数特殊形式"。
答案 1 :(得分:3)
Clojure的filter
函数需要一个或两个参数;无论哪种方式,第一个参数必须是函数。所以没有"规则"定义匿名函数的地方,只要最终,filter
的第一个参数就是函数。
但是,在这种情况下,zero?
不会返回函数,因此(zero? #(mod 6 %))
会导致filter
抛出错误。事实上,(zero? #(mod 6 %)
也没有意义,因为zero?
不会将函数作为参数。
答案 2 :(得分:2)
过滤器有两个参数:
所以,以一种简单的方式:
(defn my-predicate [x]
(zero? (mod 6 x)))
(def my-collection
(range 1 (inc 6)))
(filter
my-filter
my-collection)
#是一个clojure宏,或者为您预处理和重新组织代码的东西。我们可以使用macroexpand-1看到宏的结果:
(macroexpand-1 '#(zero? (mod 6 %)))
; (fn* [p1__4777#] (zero? (mod 6 p1__4777#)))
或更易读的代码:
(fn* [x]
(zero?
(mod 6 x))
对于集合的单个值,例如3,我们可以应用上述函数:
( (fn* [x]
(zero?
(mod 6 x)))
3)
; true
然后回到我们代码的#版本,函数的输入参数隐式为%,所以:
(
#(zero? (mod 6 %))
3)
; true
最后,回到原来的函数,你明白为什么#需要是定义过滤函数谓词的函数:
(filter
#(zero? (mod 6 %))
(range 1 (inc 6)))
; (1 2 3 6)