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

13

我是Clojure的新手,看到过像这样写的匿名函数:

(fn [x] (* x x))

而且也喜欢:

#(* % %)

显然,第二种方式更加简洁。它们之间有什么相关的区别吗?所有匿名函数都可以用任一种风格表示吗?哪种更符合习惯?

与此问题相关的是,我无法确定如何将(fn [x] [x x]) 转换为后一种语法。如果能提供一个说明这种情况的文档指针,我将不胜感激。


1
#()没有隐式的do。(fn [] ...)有。 - BillRobertson42
进一步解释@Bill的评论:https://dev59.com/imjWa4cB1Zd3GeqPtbgh - noahlz
3个回答

21
最重要的区别如下:
  • (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) 等。

1
值得一提的另一个限制是(我不知道是否可以/应该编辑您的回复),fn 允许您为函数命名,以便它们可以在函数体内引用,例如:(def fact (fn f [x] (if (= 1 x) 1 (* x (f (dec x)))))) - Gabriel Mitchell
非常感谢comppartial的建议。我想知道它们是否存在,因为我在Haskell中很欣赏它们。 - Eric Wilson

5

我无法告诉你因为这个问题我浪费了多少时间。 - BillRobertson42

2
文档中,我认为以下是最相关的区别:

惯用语法用于非常短的一次性映射/过滤函数等。

#()形式不能嵌套。

另一件事是,如果需要命名参数,则fn是更好的选择。对于#(),您将使用%或更多参数的情况下,使用%1,%2等(还有%&)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接