Yes, I know we have a lot of these.
I'm new to Clojure, but not to lisps. After the recent (javascript?) parentheses-balancing Q, I decided to do an implementation in Clojure for practice with the language. (It also happened to make a nice accompaniment to my rant about students learning what is and isn't possible with regular expressions.)
I chose to use (reduce)
over recursion mostly because I am a fan of letting functions do the work of creating loops and recursion for me, but in this case I am not sure how "elegant" I consider the :false
handling.
Code
(ns parens)
(def str->chars (partial map identity))
(defn mk-balanced?
"makes a balanced? checker from table, which maps closing characters to
opening characters.
see also: balanced?"
[table]
(fn [s]
(let [opens (set (vals table))
closes (set (keys table))]
(empty?
(reduce
(fn [stack cur]
(if (not= (peek stack) :false)
(condp contains? cur
opens (conj stack cur)
closes (if (and (seq stack)
(= (peek stack) (table cur)))
(pop stack)
[:false])
stack)
[:false]))
[]
(str->chars s))))))
(def balanced?
(mk-balanced? {\) \(
\] \[
\} \{}))
str->chars
just use(vec some-str)
. \$\endgroup\$(seq s)
is nicer to me, but thanks, that was helpful to learn (I was frustrated not to find an idiomatic version of it on my own!) \$\endgroup\$