Reputation:
i want to create 500 circles but add them only when the new circle is not collide with an existing.
so here is my loop
(let [total-circles 500
circles (loop [n 0 {:keys [x y d] :as circle} (create-circle) circles ()]
(cond
(>= n total-circles) circles
(if (not (does-circle-have-a-collision circles circle))
(recur (inc n) (create-circle) (conj circles circle))
(recur n (create-circle) circles))
:else (recur (inc n) (create-circle) circles)))])
the error message is
Syntax error (UnsupportedOperationException) compiling recur at (sketch/dynamic.clj:82:21). Can only recur from tail position
What is wrong with my code?
Upvotes: 1
Views: 188
Reputation: 413
cond
takes clauses in pairs, specifically test
/expr
pairs. That means cond
should always have an even number of forms inside it, but yours does not. Your (if ...)
form is sitting in the position of a test
without a subsequent expr
. If we abbreviate things to see the structure, it looks like this:
(cond
;; test ;; expr
(>= ...) circles
(if ...) !!!missing!!!
:else (recur ...))
One way to fix that is to pull out the test from your if
but drop the if
, like below. (Note: I rearranged your existing logic without testing it, so not sure if this will actually work, but the structure is correct. Also I put the test
/expr
pairs on separate lines and indented the expr
s so they stand out.)
(cond
;; test
;; expr
(>= n total-circles)
circles
(does-circle-have-a-collision circles circle)
(recur n (create-circle) circles)
:else
(recur (inc n) (create-circle) (conj circles circle)))
In the above, calling recur
from any expr
clause is okay.
You're keeping track of bindings in your loop
/recur
that you probably don't need. For example, you don't need to track n
when you can just check the count
of your circles collection. Let's assume you have a function
(defn add-if-no-overlap [coll c] ...)
that returns coll
with c
added if it doesn't overlap with any circle already in coll
, otherwise it returns coll
. Then you could generate your 500 non-overlapping circles like so:
(defn generate-circles [total]
(loop [circles ()]
(if (< (count circles) total)
(recur (add-if-no-overlap circles (create-circle)))
circles)))
(generate-circles 500)
Upvotes: 2
Reputation: 92147
Your cond
is badly structured. The structure should be
(cond if1 then1
if2 then2
if3 then3)
But you have
(cond if1 then1
???mystery stuff???
if2 then2)
Restructure your mystery stuff to be shaped the way that cond
expects.
Upvotes: 1