2010-12-16 14 views
42

He escrito un programa en clojure pero algunas de las funciones no tienen argumentos. ¿Cuáles serían las ventajas de codificar funciones como "def" en lugar de "defn" sin argumentos?Clojure def vs defn para una función sin argumentos

+6

Qué quiere decir '(def x (fn [] (algo)))' o '(def x (algo)) ' Son completamente diferentes, y la respuesta aceptada solo es correcta para la segunda interpretación. –

+1

Supongo que la segunda intervención, pero es un buen punto! – Zubair

Respuesta

61

def s se evalúan una sola vez mientras que defn s (con o sin argumentos) se evalúan (ejecutan) cada vez que se llaman. Por lo tanto, si sus funciones siempre devuelven el mismo valor, puede cambiarlas a def s, pero no de otra manera.

+0

¡Ah, no sabía esto, me salvaste de algunos errores graves! Entonces, si hay una definición que accede a una referencia, ¿nunca se volverá a calcular? ¿Qué pasa si el archivo se vuelve a cargar? – Zubair

+1

'def' se vuelve a evaluar cuando se vuelve a cargar el archivo. –

+3

Me parece incorrecto decir que las formas 'defn' se reevalúan. Como se señala en otras respuestas, 'defn' se resuelve a' def' en el tiempo de expansión de la macro, y de hecho todos se evalúan solo una vez en el tiempo de carga del archivo. – skuro

28

(defn name ...) es simplemente una macro que se convierte en (def name (fn ...) de todos modos, no importa cuántos parámetros tenga. Así que es solo un atajo. Consulte (doc defn) para más detalles .

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

gracias. Este ejemplo de código valía más que una descripción de 1000 palabras. – user693960

+15

Para que nadie pierda este punto crucial: como el comentario de Roman Bataev implica, '(def t2 (fn [] (System/currentTimeMillis))) 'hará que' t2' se comporte como 't1'. – Mars

8

la forma especial def crea una objeto Var identificado por un símbolo dado como primer argumento. la identificación se creó mediante la asociación del símbolo dado con un VAR en un mapa llamado espacio de nombres.

el Var tiene una referencia a algún valor, que co ULD ser expresado (entre otros):

  • como una forma constante, que siempre se evalúa a su propio valor:
    (def x 1) x ; => 1 ; x holds a reference to a number 1

  • como una forma de función, que a primera se evalúa a su valor resultante:
    (def x (+ 2 2)) x ; => 4 ; x holds a reference to a number 4

  • como una forma método Java, que en primero se evalúa a su valor resultante:
    (def x (System/currentTimeMillis)) x ; => 1417811438904 ; x holds a reference to a number 1417811438904 x ; => 1417811438904 ; still the same number!

  • como una forma lambda (función anónima), que a primera se evalúa a un objeto de función:
    (def x (fn [] (System/currentTimeMillis))) x ; => #<user$x [email protected]> (x) ; function form, function evaluated ; => 1417811438904 (x) ; function form, function evaluated ; => 1417812565866

Hay es una regla simple para todo lo anterior. En el caso de def forma especial una expresión S dado como su segundo argumento es evaluado recursivamenteantes de que se cree el enlace, por lo que el Var resultante está vinculado al resultado de esta evaluación.

Incluso fn se evalúa anteriormente, pero su valor resultante es un objeto de función que contiene un código. Este código se ejecutará (y evaluará) cada vez que se llame a la función. Es por eso que hay diferentes resultados.

La macro defn es como def pero internamente crea una función anónima y luego le une un objeto Var. Su segundo argumento se convierte en un cuerpo de esta función y no se evalúa de una manera "regular". También se podría decir que se evalúa pero como una forma lambda: el resultado de la evaluación es un objeto de función, no el resultado de un cálculo instantáneo.

por lo que escribir:
(defn fun [] 1)

es sinónimo de:
(def fun (fn [] 1))

Cuestiones relacionadas