Seem to be hitting a problem.
(defmacro cond
"Takes a set of test/expr pairs. It evaluates each test one at a
time. If a test returns logical true, cond evaluates and returns
the value of the corresponding expr and doesn't evaluate any of the
other tests or exprs. As a special case, a test of :let injects
an implicit let (the expression should be a vector of binding forms).
The new bindings may be referenced in later tests and expressions.
(cond) returns nil."
[& clauses]
(when clauses
; Jumping through many hoops, as cond is fundamental to many
; other basic forms such as let.
(if-not (next clauses)
(throw (IllegalArgumentException. "cond requires an even number
of forms")))
`(~@(if (= (first clauses) :let)
(list 'clojure.core/let (second clauses))
(list 'if (first clauses) (second clauses)))
(clojure.core/cond ~@(next (next clauses))))))
This works for normal uses of cond (I had to move it after (defn =) though).
However, when I try to use :let, I get a StackOverflowException:
at clojure.lang.PersistentList$1.doInvoke(PersistentList.java:32)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply__4293.invoke(core.clj:395)
at clojure.walk$walk__7846.invoke(walk.clj:54)
at clojure.walk$prewalk__7852.invoke(walk.clj:74)
at clojure.lang.AFn.applyToHelper(AFn.java:175)
at clojure.lang.AFn.applyTo(AFn.java:164)
at clojure.core$apply__4293.invoke(core.clj:397)
at clojure.core$partial__4968$fn__4970.doInvoke(core.clj:1639)
at clojure.lang.RestFn.invoke(RestFn.java:413)
at clojure.core$map__5005$fn__5007.invoke(core.clj:1724)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:56)
at clojure.lang.RT.seq(RT.java:440)
at clojure.lang.LazilyPersistentVector.create(LazilyPersistentVector.java:31)
at clojure.core$vec__4219.invoke(core.clj:256)
at clojure.walk$walk__7846.invoke(walk.clj:56)
at clojure.walk$prewalk__7852.invoke(walk.clj:74)
at clojure.lang.AFn.applyToHelper(AFn.java:175)
at clojure.lang.AFn.applyTo(AFn.java:164)
at clojure.core$apply__4293.invoke(core.clj:397)
at clojure.core$partial__4968$fn__4970.doInvoke(core.clj:1639)
at clojure.lang.RestFn.invoke(RestFn.java:413)
at clojure.core$map__5005$fn__5007.invoke(core.clj:1726)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:56)
at clojure.lang.Cons.next(Cons.java:37)
at clojure.lang.PersistentList$1.doInvoke(PersistentList.java:32)
I suspect this is to do with the fact that the let macro destructures
the bindings, and the function for that uses cond. I can't quite wrap
my head around the cause-and-effect however. I just don't see why it
expands infinitely, because the uses of cond inside
destructure-bindings will not be using the :let option, so any uses of
cond will be the simple working case (expanding into deeply nested
ifs).
I'm considering an alternative approach, where the cond macro is
redefined at the end of the core.clj, but that seems pretty crude and
may also not work.