Ошибка перегруженной функции, приводящая к ошибке рекурсии компилятора - PullRequest
1 голос
/ 25 августа 2011

С помощью следующего кода я получаю #<CompilerException java.lang.UnsupportedOperationException: Can only recur from tail position (NO_SOURCE_FILE:4)> несмотря на то, что все рекурсы находятся в хвостовых позициях. Если я удаляю recur из версии с одним аргументом, он перестает жаловаться. Почему это происходит?

(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? (count lst)) uniques
                      :else (cond
                              (some (partial = (first lst)) uniques)
                              (recur (rest lst) uniques)
                              :else 
                              (recur (rest lst) (first lst)))))

Ответы [ 2 ]

4 голосов
/ 25 августа 2011

Вы не разбили многоарциальные тела правильно.Должен читать (defn foo ([x] (...)) ([x y] (...))).Это заставляет компилятор думать, что вы делаете совершенно разные вещи, что, вероятно, объясняет вашу проблему.

1 голос
/ 26 августа 2011

Прежде всего: вы знаете, что все, что вам нужно, это (def remove-duplicates set) или - если вы хотите вектор - (def remove-duplicates-vec (comp vec set)), верно?

Пять вещей здесь:

  1. Как заметил Амаллой, вам следовало добавить паренсов
  2. Как заметил Котарак, вы не можете повторяться между артериями
  3. Вы не можете позвонить (set (first lst)), потому что set хочет колл. Если хотите, сделайте что-то вроде (set (vector (first [1 2 3 2 3]))), но это не красиво и не идиоматично
  4. Выполнение (cond pred1 code1 :else (cond pred2a code2a :else code2b)) можно сделать проще: (cond pred1 code1 pred2a code2a :else code2b) - то, что вы сделали, обрабатывается cond макросом , как если бы это было if (что является встроенным, насколько я знаю)
  5. Ваш последний хвостовой вызов также неверен. Предположим, мы начали с [1 2 3 2 1]
    1. Когда вы звоните сначала, у вас есть следующие аргументы: ([2 3 2 1] #{1}) (я пропустил скучную часть)
    2. Тогда у вас есть последний предикат true, поэтому вы идете с ([3 2 1] 2), и это, очевидно, неправильно, потому что вы хотели ([3 2 1] #{1 2}). Вы, вероятно, хотите позвонить (recur (rest lst) (conj uniques (first lst)))

Подводя итог:

(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))))))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...