Clojure 中的匿名函数
Anonymous function in Clojure
也许这个问题听起来很荒谬,但对我来说仍然不完全清楚匿名函数的 #
应该在哪里的区别。例如在这个例子中我过滤了一个正数的除数:
(filter #(zero? (mod 6 %)) (range 1 (inc 6))) ;;=> (1 2 3 6)
但是将 #
放在 (mod 6 %)
之前会导致错误。在这样的上下文中我的匿名函数开始的地方是否有规则,为什么 #
应该在 (zero? ...
之前?
Clojure 的 filter
函数接受一个或两个参数;无论哪种方式,第一个参数必须是 函数 。所以没有 "rule" 定义匿名函数的地方,只要最终 filter
的第一个参数是一个函数即可。
但是,在这种情况下,zero?
不是 return 函数,因此 (zero? #(mod 6 %))
会导致 filter
抛出错误。而且,事实上,(zero? #(mod 6 %)
也没有意义,因为 zero?
没有将函数作为参数。
这显示了 #(...) 语法如何只是 shorthand for (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
只是 shorthand 用于 (def divides-6 (fn [x] ...))
(即 def
和 fn
部分组合成 defn
以节省很少打字)。如果我们只打算使用该函数一次,则不需要定义全局名称 divides-6
。我们可以在将要使用的地方定义内联函数。 #(...)
语法只是一个 shorthand 版本,如示例所示。
注意表格#(...)
的全称是"anonymous function literal"。您可能还会看到它称为 "function reader macro" 或简称为 "function macro"。语法 (fn [x] ...)
称为 "function special form".
filter 有两个参数:
- 一个谓词(一个过滤器,它是一个函数),
- 一个合集
所以,简单来说:
(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)
也许这个问题听起来很荒谬,但对我来说仍然不完全清楚匿名函数的 #
应该在哪里的区别。例如在这个例子中我过滤了一个正数的除数:
(filter #(zero? (mod 6 %)) (range 1 (inc 6))) ;;=> (1 2 3 6)
但是将 #
放在 (mod 6 %)
之前会导致错误。在这样的上下文中我的匿名函数开始的地方是否有规则,为什么 #
应该在 (zero? ...
之前?
Clojure 的 filter
函数接受一个或两个参数;无论哪种方式,第一个参数必须是 函数 。所以没有 "rule" 定义匿名函数的地方,只要最终 filter
的第一个参数是一个函数即可。
但是,在这种情况下,zero?
不是 return 函数,因此 (zero? #(mod 6 %))
会导致 filter
抛出错误。而且,事实上,(zero? #(mod 6 %)
也没有意义,因为 zero?
没有将函数作为参数。
这显示了 #(...) 语法如何只是 shorthand for (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
只是 shorthand 用于 (def divides-6 (fn [x] ...))
(即 def
和 fn
部分组合成 defn
以节省很少打字)。如果我们只打算使用该函数一次,则不需要定义全局名称 divides-6
。我们可以在将要使用的地方定义内联函数。 #(...)
语法只是一个 shorthand 版本,如示例所示。
注意表格#(...)
的全称是"anonymous function literal"。您可能还会看到它称为 "function reader macro" 或简称为 "function macro"。语法 (fn [x] ...)
称为 "function special form".
filter 有两个参数:
- 一个谓词(一个过滤器,它是一个函数),
- 一个合集
所以,简单来说:
(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)