fn a defn in clojure和有什么不一样? [英] What is the difference between fn an defn in clojure?
问题描述
以下是在Clojure中编写函数的两种方法:
(defn foo [ab](+ ab))
(fn foo [ab](+ ab))
我可以这样称呼他们:
对于'defn'
(foo 1 2)
对于'fn'
(([fn foo [ab](+ ab))1 2)
'fn'似乎没有将其可选名称插入当前范围,而'defn'似乎恰好做到了这一点。具有两种创建函数的方式是否还有其他区别或原因?是否有一个我们不仅仅使用'fn'的原因?
(fn foo [ab](+ ab) )
(foo 1 2)
<基本将code> defn 定义为*:
(defmacro defn [name args& body]
`[def〜name(fn〜args〜@ body)))
或者换句话说,您可以基本上写:
( defn my-func [a]
(东西a))
As *:
(def my-func
(fn [a](东西a)))
仅使用 fn
创建一个匿名函数,该函数不会单独绑定任何符号在外部。必须使用 let
或 def
绑定它才能在其外部引用。
通过定义 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:在clojure.lang.Numbers.divide上除以零
(Numbers.java:158)
在clojure.lang.Numbers.divide(Numbers.java:3808)
在digital_rain.core $ my_func $ my_inner_func__2320.invoke(form-init1838550899342340522.clj:2)
在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
的基本胆识可能会让您有些头疼。
Here are two of the ways to write functions in Clojure:
(defn foo [a b] (+ a b))
(fn foo [a b] (+ a b))
I can call them like so:
In the case of 'defn'
(foo 1 2)
In the case of 'fn'
((fn foo [a b] (+ a b)) 1 2)
'fn' doesn't seem to insert its optional name into the current scope, where 'defn' seems to do exactly that. Is there any other difference or reason for having two ways of creating functions? Is there a reason we don't just use 'fn' like this:
(fn foo [a b] (+ a b))
(foo 1 2)
defn
is basically defined as*:
(defmacro defn [name args & body]
`(def ~name (fn ~args ~@body)))
Or in other words, you could basically write:
(defn my-func [a]
(stuff a))
As*:
(def my-func
(fn [a] (stuff a)))
Using just fn
creates an anonymous function that alone isn't bound to any symbol externally. It must be bound using let
or def
to be referred to outside of itself.
By having defn
defined in terms of def
and fn
, the responsibilies of binding a function to a symbol (as well as all the other complexities that come with it) and handling function behaviour can be separated.
When you supply a name for fn
, it can't be referred to outside of the function, but it can be used to refer to itself to create a recursive anonymous function:
(fn my-func [n] (my-func (inc n))
And, it gives the function a slightly nicer name to show up in stack traces to ease debugging:
(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)
*
These are gross understatements and a tad misleading, but they simplify things.
In reality, defn
isn't defined using defmacro
; defmacro
is actually defined using defn
. defn
also adds some good stuff like pre/post condition checking, documentation, and other meta information; but that's not as relevant here. I recommend looking over its source for a more in-depth look; although it's pretty convoluted. The fundamental guts of clojure.core
can be a little daunting to wrap your head around.
这篇关于fn a defn in clojure和有什么不一样?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!