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?
def
s sont évalués une seule fois alors que les defn
s (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 def
s mais pas autrement.
user=> (def t0 (System/currentTimeMillis))
user=> (defn t1 [] (System/currentTimeMillis))
user=> (t1)
1318408717941
user=> t0
1318408644243
user=> t0
1318408644243
user=> (t1)
1318408719361
(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.
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))