在clojure中fn和defn有什么区别?

Min*_*wth 6 clojure

以下是在Clojure中编写函数的两种方法:

(defn foo [a b] (+ a b))
(fn foo [a b] (+ a b))
Run Code Online (Sandbox Code Playgroud)

我可以这样称呼它们:

在'defn'的情况下

(foo 1 2)
Run Code Online (Sandbox Code Playgroud)

在'fn'的情况下

((fn foo [a b] (+ a b)) 1 2)
Run Code Online (Sandbox Code Playgroud)

'fn'似乎没有将其可选名称插入当前范围,其中'defn'似乎就是这样做的.有两种创建函数的方法还有其他差异或原因吗?有没有理由我们不像这样使用'fn':

(fn foo [a b] (+ a b))
(foo 1 2)
Run Code Online (Sandbox Code Playgroud)

Car*_*ate 15

defn基本上定义为*:

(defmacro defn [name args & body]
  `(def ~name (fn ~args ~@body)))
Run Code Online (Sandbox Code Playgroud)

或者换句话说,你基本上可以写:

(defn my-func [a]
  (stuff a))
Run Code Online (Sandbox Code Playgroud)

如*:

(def my-func
  (fn [a] (stuff a)))
Run Code Online (Sandbox Code Playgroud)

使用just只fn创建一个匿名函数,它不会在外部绑定任何符号.它必须使用letdef在其自身之外引用.

通过具有defn在来定义deffn的函数,结合到符号responsibilies(以及所有随之而来的其他复杂)和处理功能行为可以被分离.

当您为其提供名称时fn,它不能在函数外部引用,但它可以用于引用自身来创建递归匿名函数:

(fn my-func [n] (my-func (inc n))
Run Code Online (Sandbox Code Playgroud)

并且,它为函数提供了一个稍微好一点的名称,以便在堆栈跟踪中显示以简化调试:

(defn my-func []
  ((fn my-inner-func [] (/ 1 0))))
=> #'digital-rain.core/my-func

(my-func)
java.lang.ArithmeticException: Divide by zero
    at clojure.lang.Numbers.divide(Numbers.java:158)
    at clojure.lang.Numbers.divide(Numbers.java:3808)
    at digital_rain.core$my_func$my_inner_func__2320.invoke(form-init1838550899342340522.clj:2)
    at digital_rain.core$my_func.invokeStatic(form-init1838550899342340522.clj:2)
    at digital_rain.core$my_func.invoke(form-init1838550899342340522.clj:1)
Run Code Online (Sandbox Code Playgroud)

*这些都是粗略的轻描淡写,有点误导,但它们简化了事情.实际上,defn没有定义使用defmacro; defmacro实际上定义使用defn.defn还添加了一些好东西,如前/后条件检查,文档和其他元信息; 但这并不重要.我建议查看其来源以获得更深入的外观; 虽然它很复杂.clojure.core包围你的头脑的基本内容可能有点令人生畏.