fn a defn in clojure和有什么不一样? [英] What is the difference between fn an defn in clojure?

查看:97
本文介绍了fn a 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆