以下是在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)
答案 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
创建一个匿名函数,该函数不会在外部绑定任何符号。必须使用let
或def
绑定它才能在自身之外引用。
根据defn
和def
定义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))