Clojure中匿名函数的fn和#语法之间有区别吗?

Is there a difference between the fn and # syntax for anonymous functions in Clojure?

我是Clojure的新手,并且我已经看到匿名函数的编写方式如下:

1
(fn [x] (* x x))

也喜欢:

1
#(* % %)

显然,第二个更为简洁。 有什么相关的区别吗? 每个匿名函数都可以用两种样式表示吗? 还有一种惯用的吗?

与此问题相关,我无法确定如何将(fn [x] [x x])转换为后一种语法。 我希望能找到可以澄清这种情况的文档。


最重要的区别是:

  • (fn ...)可以嵌套,#()不能嵌套
  • 您可以使用(fn [x y] ..)或类似名称更好地命名参数,而不是使用%%2%3等。
  • 您可以使用(fn ...)命名函数以进行递归使用,例如(fn fib [n] (if (<= n 1) 1 (+ (fib (- n 1)) (fib (- n 2)))))
  • 代码生成/操作(fn [...] ...)更容易,因为#()是阅读器宏而不是常规的Clojure形式。
  • #()更简洁。但是,如果这是主要考虑因素,则可能您的优先级有误:-)

我个人的建议是:

  • 在大多数情况下,首选(fn [...] ...)
  • 仅将#()用于非常短的内联函数,例如(map #(+ 2 %) (range 10))
  • 还应考虑通过高阶函数生成匿名函数可能比将它们显式写出更好。 (comp func1 func2)(partial func param1 param2)


另一个SO答案(Clojure开发人员应避免的常见编程错误)提到#([% %])扩展为fn [%] ([% %])(请注意括号),这会导致ArityException。

您可以执行#(vector % %)来解决此限制。


从文档中,我认为这些是最相关的区别:

idiomatic used would be for very short one-off mapping/filter fns and the like.

#() forms cannot be nested.

另一件事是,如果需要命名参数,则fn是更好的选择。对于#(),将使用%,或者对于一个以上的参数,将使用诸如%1,%2等(以及%&)。