2009-08-02 8 views
4

Je souhaite effectuer les opérations imbriquées suivantes jusqu'à ce que l'expérience soit satisfaite. Existe-t-il un mot-clé: until qui arrête de faire d'autres opérations lorsque la condition correspond.Y a-t-il une commande ": until" dans clojure?

Cette commande génère le Triplet de Pythagore 3 4 5. Je ne veux pas qu'il fasse quoi que ce soit d'autre une fois arrivé à cette séquence de nombres.

(for [a (range 1 100) 
     b (range 1 100) 
     c (list (Math/sqrt (+ (Math/pow (int a) 2) (Math/pow (int b) 2)))) 
     :when (= 12 (+ a b c))] 
    (list a b c)) 
+1

Vous ne pouvez pas "pas" le conditionnel? – jrockway

Répondre

9

:while est un test de court-circuit dans for expressions. Les éléments de liste seront générés jusqu'à la première fois qu'ils rencontrent un test défaillant.

Dans votre cas

(for [<code omitted> :while (not (= 12 (+ a b c)))] (list a b c)) 

arrêterait génération d'éléments dès qu'il a trouvé le triplet Rajouté à 12.

Un problème cependant, il ne fait pas ce que vous attendez. Le triplet lui-même ne ferait pas partie du résultat puisqu'il échoué le test.

La compréhension d'une liste n'est peut-être pas la meilleure solution si vous recherchez uniquement un résultat unique. Pourquoi ne pas simplement utiliser une boucle?

(loop [xs (for [a (range 1 100) 
       b (range 1 100)] [a, b])] 
    (when (seq xs) 
    (let [[a, b] (first xs) 
      c (Math/sqrt (+ (Math/pow (int a) 2) 
          (Math/pow (int b) 2)))] 
     (if (not (= 12 (+ a b c))) 
     (recur (next xs)) 
     (list a b c))))) 
+0

J'ai beaucoup appris de ce code. Juste quelques questions: 1.Quel type fait (pour ....) générer? 2.Pourquoi as-tu besoin de (seq xs)? – unj2

+0

1) Une séquence paresseuse. 2) Pour vérifier le cas où xs est vide: (seq xs) retournera zéro quand xs est vide, échouant ainsi le test et quittant la boucle. C'est un idiome assez commun dans Clojure. – alanlcode

6

Depuis for donne une lazy séquence vous obtiendrez le résultat souhaité en choisissant le premier élément:

(first (for [a (range 1 100) 
      b (range 1 100) 
      c (list (Math/sqrt (+ (Math/pow (int a) 2) 
            (Math/pow (int b) 2)))) 
      :when (= 12 (+ a b c))] 
      (list a b c)) 

Seul le premier élément de la liste générée est calculée en raison de la paresse, qui peut être démontrée avec un effet secondaire:

user=> (first 
     (for [a (range 1 100) 
       b (range 1 100) 
       c (list (Math/sqrt (+ (Math/pow (int a) 2) 
            (Math/pow (int b) 2)))) 
       :when (= 12 (+ a b c))] 
      (do (println "working...") 
       (list a b c)))) 
working... 
(3 4 5.0) 

(for ...) viennent s avec un: let modificateur donc il n'y a pas besoin d'envelopper c dans une liste:

(for [a (range 1 100) 
     b (range 1 100) 
     :let [c (Math/sqrt (+ (Math/pow (int a) 2) 
          (Math/pow (int b) 2)))] 
     :when (= 12 (+ a b c))] 
    (list a b c)) 
+0

+1 pour la solution la plus fonctionnelle. – firefrorefiddle

Questions connexes