50 votes

Comment retourner d'une fonction de manière anticipée en Clojure ?

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 ?

59voto

Ben Kovitz Points 721

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

31voto

Joost Diepenmaat Points 11436

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.

17voto

Chuck Points 138930

À 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.

15voto

Diego Sevilla Points 17274

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.

1voto

prnsml Points 634

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)))))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X