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
会创建一个匿名函数,它本身不与任何外部符号绑定。必须使用let
或def
将其绑定才能在其外部引用。
通过使用def
和fn
来定义defn
,可以分离绑定函数到符号(以及所有相关的复杂性)和处理函数行为的责任。
当您为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
还添加了一些好东西,比如前/后条件检查,文档和其他元信息;但这对这里并不那么相关。我建议查看其源代码以进行更深入的了解;虽然它相当复杂。 clojure.core
的基本核心可能有点令人生畏。