Question

J'essaie de clojurer j'essaie de comprendre comment implémenter l'algorithme suivant,

Je lis un flux d'entrée que je veux continuer à lire jusqu'à ce que ce ne soit plus un caractère délimiteur.

Je peux le faire en java avec une boucle while mais je n'arrive pas à comprendre comment le faire en clojure?

while
   read
   readChar != delimiter

   do some processing....
end while
Était-ce utile?

La solution

Je ne connais pas Clojure, mais il semble que, comme Scheme, il prenne en charge & "let loops &";:

(loop [char (readChar)]
   (if (= char delimiter)
       '()
       (do (some-processing)
           (recur (readChar)))))

J'espère que cela suffit pour vous aider à démarrer. J'ai mentionné qu'il fallait http://clojure.org/special_forms#toc9 pour répondre à cette question.

REMARQUE: je sais que Clojure décourage les effets secondaires. Par conséquent, vous souhaitez sans doute renvoyer quelque chose d’utile au lieu de '().

Autres conseils

Travailler sur Clojure 1.3.0, et pour ce que cela vaut, vous pouvez maintenant écrire en boucle dans Clojure en faisant quelque chose qui ressemble à

(while truth-expression
  (call-some-function))

L’approche de la boucle fonctionnera bien en boucle mais la boucle / récurrence est considérée comme une opération de bas niveau et les fonctions d’ordre supérieur généralement préférées

Normalement, ce genre de problème serait résolu en créant une séquence de jetons (les caractères dans votre exemple) et en appliquant une ou plusieurs fonctions de la séquence de clojure (doseq, dorun, à prendre, etc.)

L'exemple suivant lit le premier nom d'utilisateur dans / etc / passwd sur des systèmes similaires à Unix.

(require '[clojure.java [io :as io]])

(defn char-seq
  "create a lazy sequence of characters from an input stream"
  [i-stream]
  (map char 
   (take-while
    (partial not= -1)
    (repeatedly #(.read i-stream)))))

;; process the sequence one token at a time
;; with-open will automatically close the stream for us 

(with-open [is (io/input-stream "/etc/passwd")]
  (doseq [c (take-while (partial not= \:) (char-seq is))]
    ;; your processing is done here
    (prn c)))

Je l’ai imaginé dans l’esprit de line-seq. C'est complètement paresseux et montre plus de la nature fonctionnelle de Clojure que loop.

(defn delim-seq
  ([#^java.io.Reader rdr #^Character delim]
     (delim-seq rdr delim (StringBuilder.)))
  ([#^java.io.Reader rdr #^Character delim #^StringBuilder buf]
     (lazy-seq
       (let [ch (.read rdr)]
         (when-not (= ch -1)
           (if (= (char ch) delim)
             (cons (str buf) (delim-seq rdr delim))
             (delim-seq rdr delim (doto buf (.append (char ch))))))))))

Pâte complète .

Une boucle while implique généralement des variables modifiables, c’est-à-dire attendre que la variable remplisse une certaine condition; Dans Clojure, vous utiliseriez généralement la récursion de la queue (que le compilateur traduit en boucle while)

Ce qui suit n’est pas tout à fait une solution, mais cette variante de la boucle for pourrait être utile dans certains cas:

(for [a (range 100) 
      b (range 100) 
      :while (< (* a b) 1000)] 
    [a b]
  )

Ceci créera une liste de toutes les paires de a et b jusqu'à (< (* a b) 1000). C’est-à-dire qu’il s’arrêtera dès que la condition sera remplie. Si vous remplacez: tandis que par: quand, vous pourrez trouver tous les couples qui remplissent la condition, même après en avoir trouvé un qui ne l’est pas.

Je suis sorti avec cette version:

(defn read-until
  [^java.io.Reader rdr ^String delim]
  (let [^java.lang.StringBuilder salida (StringBuilder.) ]
    (while
      (not (.endsWith (.toString salida) delim))
      (.append salida (str (char (.read rdr))))
    )
    (.toString salida)
  )
)

Il recherche une chaîne, pas un seul caractère comme délimiteur!

Merci!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top