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

时间:2018-03-09 01:35:04

标签: clojure

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

(defn foo [a b] (+ a b))
(fn foo [a b] (+ a b))

我可以这样称呼他们:

在' defn'

的情况下
(foo 1 2)

对于' fn'

((fn foo [a b] (+ a b)) 1 2)

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

(fn foo [a b] (+ a b))
(foo 1 2)

2 个答案:

答案 0 :(得分:14)

defn 基本上定义为*:

(defmacro defn [name args & body]
  `(def ~name (fn ~args ~@body)))

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

(defn my-func [a]
  (stuff a))

作为*:

(def my-func
  (fn [a] (stuff a)))

仅使用fn创建一个匿名函数,该函数不会在外部绑定任何符号。必须使用letdef绑定它才能在自身之外引用。

根据defndef定义fn,将函数绑定到符号的责任(以及随附的所有其他复杂性)和处理功能行为可以分开。

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

(fn my-func [n] (my-func (inc n))

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

(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)

*这些都是轻描淡写,有点误导,但它们简化了事情。实际上,使用defn未定义defmacro; defmacro实际上是使用defn定义的。 defn还添加了一些好的东西,比如前/后条件检查,文档和其他元信息;但这并不重要。我建议查看其source以获得更深入的了解;虽然它很复杂。 clojure.core的基本内容可能会让你头晕目眩。

答案 1 :(得分:0)

fn:定义函数obj,但不为其指定名称。当您要创建匿名类时,这很好。要给它起一个名字,您需要使用def:

(def greet (fn [name] (str "Hello, " name)))

另一方面,defn定义一个函数并为其命名:

(defn greet [name] (str "Hello, " name))