我已经用Clojure语言写了一个程序,但其中一些函数没有参数。将这些函数用"def"定义与使用"defn"定义但不带参数的方式相比,有哪些优点呢?
我已经用Clojure语言写了一个程序,但其中一些函数没有参数。将这些函数用"def"定义与使用"defn"定义但不带参数的方式相比,有哪些优点呢?
(def t0 (System/currentTimeMillis))
(defn t1 [] (System/currentTimeMillis))
(t1)
;; => 1318408717941
t0
;; => 1318408644243
t0
;; => 1318408644243
(t1)
;; => 1318408719361
(def t2 (fn [] (System/currentTimeMillis)))
将使t2
的行为类似于t1
。 - Marsdef
仅评估一次,而defn
(带参数或不带参数)每次调用时都会评估(执行)。因此,如果您的函数始终返回相同的值,则可以将它们更改为def
,否则不能。
def
会被重新评估。 - Abhinav Sarkardefn
表达式被重新评估是错误的。正如其他回答所指出的那样,defn
在宏展开时解析为 def
,它们确实只在文件加载时被评估一次。 - skurodefn
和每个def
一样只会被评估一次,这里它定义了一个函数。然而,所定义函数的主体可以被评估任意次数。我认为这并没有什么用处,但他说的也不是错的。 - amalloy(def x (fn [] (do-something-here)))
,而你似乎将其解释为(defn x [] (do-something-here))
。如果提问者能够具体说明哪种解释是正确的,那就好了。 - Charles Duffy(defn name ...) 只是一个宏,无论它有多少参数,最终都会转换成 (def name (fn ...))。因此,它只是一种快捷方式。有关详细信息,请参见 (doc defn)。
def
特殊形式创建一个由其第一个参数作为标识符的 Var 对象。通过将给定的符号与名为命名空间的映射中的 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
(def x (System/currentTimeMillis))
x
;; => 1417811438904 ; x holds a reference to a number 1417811438904
x
;; => 1417811438904 ; still the same number!
(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))
(def x (fn [] (something)))
还是(def x (something))
?它们完全不同,而被接受的答案仅对第二种解释正确。 - Charles Duffy