Common Lisp a return-from
; y a-t-il une sorte de return
en Clojure pour quand vous voulez retourner tôt d'une fonction ?
Réponses
Trop de publicités?Lorsque vous avez besoin de sortir prématurément d'un calcul, vous avez besoin d'un moyen de le faire, pas d'un argument de puristes. En général, vous en avez besoin lorsque vous réduisez une grande collection et qu'une certaine valeur indique qu'il est inutile de poursuivre le traitement de la collection. À cette fin, le toujours pratique Clojure fournit la fonction reduced
fonction.
Un exemple simple pour illustrer cela est que lorsque vous multipliez une séquence de nombres, si vous rencontrez un zéro, vous savez déjà que le résultat final sera zéro, donc vous n'avez pas besoin de regarder le reste de la séquence. Voici comment coder cela avec reduced
:
(defn product [nums]
(reduce #(if (zero? %2)
(reduced 0.0)
(* %1 %2))
1.0
nums))
reduced
enveloppe la valeur que vous lui donnez dans une structure de données sentinelle de sorte que reduce
sait qu'il faut arrêter de lire la collection et simplement renvoyer l'adresse de l'utilisateur. reduced
valeur en ce moment. Hé, c'est purement fonctionnel, même !
Vous pouvez voir ce qui se passe si vous enroulez l'image ci-dessus. if
dans un do
avec un (println %1 %2)
:
user=> (product [21.0 22.0 0.0 23.0 24.0 25.0 26.0])
1.0 21.0
21.0 22.0
462.0 0.0
0.0
user=> (product [21.0 22.0 23.0 24.0 25.0 26.0])
1.0 21.0
21.0 22.0
462.0 23.0
10626.0 24.0
255024.0 25.0
6375600.0 26.0
1.657656E8
Il n'y a pas d'instruction de retour explicite en clojure. Vous pourriez bricoler quelque chose en utilisant une combinaison catch/throw si vous le souhaitez, mais comme clojure est beaucoup plus fonctionnel que common lisp, les chances que vous fassiez réellement un retour sont très faibles. necesito un retour anticipé en plein milieu d'un bloc imbriqué est beaucoup plus faible qu'en CL. La seule "bonne" raison que je vois pour les déclarations de retour est lorsque vous traitez des objets mutables d'une manière qui n'est pas idiomatique en clojure.
Je n'irais pas jusqu'à dire que ce n'est jamais utile, mais je pense que dans Clojure, si votre algorithme a besoin d'une déclaration de retour, c'est une odeur de code majeure.
À moins que vous n'écriviez un code vraiment funky, la seule raison pour laquelle vous voudriez retourner un résultat anticipé est qu'une condition est remplie. Mais comme les fonctions renvoient toujours le résultat de la dernière forme évaluée, if
est déjà cette fonction - il suffit de mettre la valeur que vous voulez renvoyer dans le corps de la fonction if
et il renverra cette valeur si la condition est remplie.
Je ne suis pas un expert de Clojure, mais il semble qu'il ne dispose pas de ces constructions pour essayer d'être plus fonctionnel. Jetez un coup d'oeil à ce que dit Stuart Halloway aquí :
Common Lisp prend également en charge une macro return-from pour "retourner" du milieu d'une fonction. Cela encourage un style de programmation impératif impératif, que Clojure décourage.
Cependant, vous pouvez résoudre les mêmes problèmes d'une manière différente. Voici l'exemple l'exemple de return-from, réécrit dans un style fonctionnel de façon à ce qu'aucun return-from n'est pas nécessaire :
(defn pair-with-product-greater-than [n]
(take 1 (for [i (range 10) j (range 10) :when (> (* i j) n)] [i j])))
C'est-à-dire utiliser des séquences paresseuses et renvoyer des valeurs en fonction de conditions.
Comme alternative, vous pouvez utiliser cond . Et si dans certaines conditions vous devez évaluer plusieurs expressions, utilisez hacer . Voici un exemple :
(defn fact [x]
(cond
(< x 0) (do (println (str x " is negative number"))
(throw (IllegalArgumentException. "x should be 0 or higher")))
(<= x 1) 1
:else (* x (fact (- x 1)))))
- Réponses précédentes
- Plus de réponses