开发者

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:

  1. As amalloy noticed, you should've added parens
  2. As kotarak noticed, you can't recur between arities
  3. You can't call (set (first lst)) because set wants coll. If you want, do something like (set (vector (first [1 2 3 2 3]))) but this is neither pretty nor idiomatic
  4. 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 treated cond macro as if it were if (which is a built-in as far as I know)
  5. Your last tail-call is also wrong. Assume we've started with [1 2 3 2 1]
    1. When you call it first you have following arguments: ([2 3 2 1] #{1}) (I've skipped the boring part)
    2. 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)))

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))))))
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜