web-dev-qa-db-fra.com

Clojure def vs defn pour une fonction sans arguments

J'ai écrit un programme en clojure mais certaines fonctions n'ont pas d'arguments. Quels seraient les avantages de coder de telles fonctions comme un "def" au lieu d'un "defn" sans arguments?

48
Yazz.com

defs sont évalués une seule fois alors que les defns (avec ou sans arguments) sont évalués (exécutés) à chaque fois qu'ils sont appelés. Donc, si vos fonctions renvoient toujours la même valeur, vous pouvez les changer en defs mais pas autrement.

75
Abhinav Sarkar
user=> (def t0 (System/currentTimeMillis))
user=> (defn t1 [] (System/currentTimeMillis))
user=> (t1)
1318408717941
user=> t0
1318408644243
user=> t0
1318408644243
user=> (t1)
1318408719361
111
jamesqiu

(defn name ...) est juste une macro qui se transforme en (def name (fn ...) de toute façon, peu importe le nombre de paramètres dont elle dispose. C'est donc juste un raccourci. Voir (doc defn) pour plus de détails.

39
Roman Bataev

La forme spéciale def crée un objet Var identifié par un symbole donné comme premier argument. L'identification est créée en associant le symbole donné à une Var dans une carte appelée espace de noms.

Le Var détient ne référence à une valeur, qui pourrait être exprimé (entre autres):

  • comme une forme constante, qui évalue toujours à sa propre valeur:
    (def x 1) x ; => 1 ; x holds a reference to a number 1

  • comme une forme de fonction, qui dans un premier temps est évaluée à sa valeur résultante:
    (def x (+ 2 2)) x ; => 4 ; x holds a reference to a number 4

  • sous forme de Java, qui au début est évalué à sa valeur résultante:
    (def x (System/currentTimeMillis)) x ; => 1417811438904 ; x holds a reference to a number 1417811438904 x ; => 1417811438904 ; still the same number!

  • comme une forme lambda (fonction anonyme), qui dans un premier temps est évaluée à un objet fonction:
    (def x (fn [] (System/currentTimeMillis))) x ; => #<user$x user$x@4c2b1826> (x) ; function form, function evaluated ; => 1417811438904 (x) ; function form, function evaluated ; => 1417812565866

Il existe une règle simple pour tout ce qui précède. Dans le cas d'une forme spéciale def, une expression S donnée comme deuxième argument est évaluée récursivementavant la création de la liaison, donc le Var résultant est lié au résultat de cette évaluation.

Même fn est évalué avant, mais sa valeur résultante est un objet fonction contenant un code. Ce code sera exécuté (et évalué) chaque fois que la fonction est appelée. C'est pourquoi il y a des résultats différents.

La macro defn est exactement comme def mais en interne, elle crée une fonction anonyme et y lie ensuite un objet Var. Son deuxième argument devient un corps de cette fonction et il n'est pas évalué de manière "régulière". On pourrait aussi dire qu'il est évalué mais sous forme lambda - le résultat de l'évaluation est un objet fonction, pas le résultat d'un calcul instantané.

Alors en écrivant:
(defn fun [] 1)

Est synonyme de:
(def fun (fn [] 1))

11
siefca