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

Reply via email to