对于没有参数的函数,Clojure def vs defn

时间:2010-12-16 13:40:57

标签: clojure

我在clojure中编写了一个程序,但是有些函数没有参数。将这样的函数编码为“def”而不是没有参数的“defn”会有什么好处?

4 个答案:

答案 0 :(得分:107)

user=> (def t0 (System/currentTimeMillis))
user=> (defn t1 [] (System/currentTimeMillis))
user=> (t1)
1318408717941
user=> t0
1318408644243
user=> t0
1318408644243
user=> (t1)
1318408719361

答案 1 :(得分:73)

def仅被评估一次,而defn s(有或没有参数)在每次被调用时被评估(执行)。因此,如果您的函数始终返回相同的值,则可以将它们更改为def,但不能将其更改为

答案 2 :(得分:37)

(defn name ...)只是一个变成(def name(fn ...)的宏,无论它有多少参数。所以它只是一个捷径。详见(doc defn)。

答案 3 :(得分:10)

def特殊表单创建一个 Var 对象,该对象由作为其第一个参数的符号标识。通过将给定符号与名为namespace的映射中的Var相关联来创建标识。

Var持有对某个值的引用,可以表达(等等):

  • 作为常量形式,始终评估为自己的值
    (def x 1) x ; => 1 ; x holds a reference to a number 1

  • 作为一种功能形式,首先将评估为其结果值
    (def x (+ 2 2)) x ; => 4 ; x holds a reference to a number 4

  • 作为Java方法表单,首先将计算为其结果值
    (def x (System/currentTimeMillis)) x ; => 1417811438904 ; x holds a reference to a number 1417811438904 x ; => 1417811438904 ; still the same number!

  • 作为lambda表单(匿名函数),首先将计算为函数对象
    (def x (fn [] (System/currentTimeMillis))) x ; => #<user$x user$x@4c2b1826> (x) ; function form, function evaluated ; => 1417811438904 (x) ; function form, function evaluated ; => 1417812565866

上述所有内容都有一个简单的规则。在def特殊形式的情况下,作为第二个参数给出的S表达式在创建绑定之前递归计算 ,因此生成的Var绑定到结果评估。

之前评估了fn,但其结果值是一个包含代码的函数对象。每次调用函数时,都会执行(并评估)代码。这就是为什么会有不同的结果。

defn宏就像def一样,但在内部创建了一个匿名函数,然后将一个Var对象绑定到它。它的第二个参数成为这个函数的一个主体,它没有以“常规”的方式进行评估。也可以说它被评估但是作为一种lambda形式 - 评估的结果是一个函数对象,而不是一些即时计算的结果。

所以写作:
(defn fun [] 1)

是同义词:
(def fun (fn [] 1))