2009/7/3 Christophe Grand <christo...@cgrand.net>: > Hi all! > > On Thu, Jul 2, 2009 at 11:09 PM, Laurent PETIT <laurent.pe...@gmail.com> > wrote: >> >> (def push conj) >> (def closing-counterpart { \( \), \[ \] }) >> (def opening-char? closing-counterpart) >> (defn matching-pair? [left right] (= right (closing-counterpart left))) >> >> (defn consume-one [stack c] >> (if (or (opening-char? c) >> (not (matching-pair? (peek stack) c))) >> (push stack c) >> (pop stack))) >> >> (defn balanced? [s] >> (empty? (reduce consume-one [] s))) >> >> (defn main [] >> (apply print (map balanced? *command-line-args*))) >> >> (when *command-line-args* >> (main)) > > I think you don't need opening-char? > > (defn balanced? [s] > (let [tr {\( \) \[ \]}] > (empty? > (reduce #(if (= (peek %1) %2) > (pop %1) > (conj %1 (tr %2))) [] s)))) > > I push "transposed" characters on the stack, thus only \] \) or nil can be > on the stack. > Since nil isn't equal to a character, it will never be popped and thus it > ensures the stack will not be empty. > > >> >> It's the second time I wish I had a version of reduce that allows to >> quit the reduction early. > > > You're not alone Laurent but I'm not sure that's a simple reduce-while is > possible (I can't decide which values to test for early exit (accumulated > result or accumulated result + item) and when (before or after calling the > reducing function)).
Indeed, not easy to be general, concise and elegant at the same time here ... What about: "(reduce-until pred reductor init-acc coll)" ? pred would be a function of acc (the accumulator) and i (next item from coll), be executed before reductor, and return * nil or false for continuing, * a vector with a specific return value (which could be acc or something else) * special meaning keyword :next for reduce-until to return the final call of reductor on acc and i (this one could be got rid of, though ?) e.g. : my version would become (defn consume-one [stack c] (cond (opening-char? c) (push stack c) (matching-pair? (peek stack) c) (pop stack))) (defn balanced? [s] (empty? (reduce-until #(when-not (consume-one %1 %2) [[:error]]) consume-one [] s))) or yours: (defn balanced? [s] (let [tr {\( \) \[ \]}] (empty? (reduce-until (fn [acc v] (when (nil? (get acc 0 true)) [acc])) #(if (= (peek %1) %2) (pop %1) (conj %1 (tr %2))) [] s)))) But all in all I don't find this is much a readability or composability improvement ..., or is this ? Regards, -- Laurent --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---