Overloaded function failing giving Compiler recursion error
With the following code, I get #<CompilerException java.lang.UnsupportedOperationException: Can only recur from tail position (NO_SOURCE_FILE:4)>
despite the fact that all recurs are in tail positions. If I remove the recur from the one-argument version, it stops complaining. Why is this happening?
(defn remove-duplicates "Removes duplicate elements of lst.
For example, given (1 2 3 1 4 1 2), remove-duplicates returns a sequence
containing the elements (1 2 3 4), in some order."
[lst] (recur (rest lst) (set (first lst)))
[lst uniques] (cond (zero? (coun开发者_StackOverflow中文版t lst)) uniques
:else (cond
(some (partial = (first lst)) uniques)
(recur (rest lst) uniques)
:else
(recur (rest lst) (first lst)))))
You haven't split up the multi-arity bodies right. Should read (defn foo ([x] (...)) ([x y] (...)))
. This causes the compiler to think you're doing totally different stuff, which probably accounts for your issue.
First of all: you know that all you want is (def remove-duplicates set)
or -- if you want a vector -- (def remove-duplicates-vec (comp vec set))
, right?
Five things here:
- As amalloy noticed, you should've added parens
- As kotarak noticed, you can't recur between arities
- You can't call
(set (first lst))
becauseset
wants coll. If you want, do something like(set (vector (first [1 2 3 2 3])))
but this is neither pretty nor idiomatic - Doing
(cond pred1 code1 :else (cond pred2a code2a :else code2b))
could be made simplier:(cond pred1 code1 pred2a code2a :else code2b)
-- what you did is treatedcond
macro as if it wereif
(which is a built-in as far as I know) - Your last tail-call is also wrong. Assume we've started with
[1 2 3 2 1]
- When you call it first you have following arguments:
([2 3 2 1] #{1})
(I've skipped the boring part) - Then you have last predicate true, so you go with
([3 2 1] 2)
and this is obviously wrong because you wanted([3 2 1] #{1 2})
. You probably want to call(recur (rest lst) (conj uniques (first lst)))
- When you call it first you have following arguments:
Summing up:
(defn remove-duplicates
([lst] (remove-duplicates (rest lst) #{(first coll)}))
([lst uniques]
(cond
(zero? (count lst)) uniques
(some (partial = (first lst)) uniques)
(recur (rest lst) uniques)
:else
(recur (rest lst) (conj uniques (first lst))))))
精彩评论