Clojure: возвращаемое значение оценивается - PullRequest
1 голос
/ 01 апреля 2012

* Простой вопрос: почему эта функция выдает исключение при оценке?*

  • В случае, если в строке есть дубликат, при его обнаружении возникает исключение приведения класса.

  • В случае, если строка не имеет дубликатов, генерируется исключение NullPointerException.

* Код *

(defn first-duplicate-char [str-in]
      (loop [list-Rem (seq str-in) set-Seen (set [])]
        (print (type list-Rem) " " list-Rem (next list-Rem) "\n")
        (if (= 0 (count str-in))
            nil
            (if (some #(= (first list-Rem) %) set-Seen)
                (first list-Rem)
                (recur  
                    (seq (next list-Rem))
                    (conj set-Seen (first list-Rem)))))))

1 Ответ

2 голосов
/ 01 апреля 2012

Ваша проблема в том, что (= 0 (count str-in)) никогда не меняется, поэтому вы в конечном итоге пытаетесь вызвать first на nil. [ РЕДАКТИРОВАТЬ: Я не прав, ваш код на самом деле работает как есть - то, что оператор просто не работает. Надеюсь, вам все равно понравится этот ответ.]

Вместо этого вы должны вызывать next (не rest) на list-Rem в recur и использовать list-Rem непосредственно в тесте if, используя свойство next, которое возвращает nil для пустой последовательности. Вот как бы я переписал твой код:

(defn first-duplicate [in]
  (loop [seen #{}
         remain (seq in)]
    (when-let [[head & tail] remain]
      (if (contains? seen head)
        head
        (recur (conj seen head) tail)))))

Изменения:

  • строчные имена
  • нет необходимости вызывать seq на выходе next или rest
  • с наборами, contains? (проверка на наличие ключа) быстрее, чем some (запуск предиката для элементов, пока что-то не даст истинное значение)
  • установить буквальный
  • с использованием when для возврата nil при неудачном тесте
  • с использованием when-let для деструкции и связывания первого символа и отдыха

Стилистические изменения:

  • имена изменены, чтобы быть менее конкретными (например, не ограничиваясь строками)
  • изменить порядок локальных циклов так, чтобы recur больше походил на структурную рекурсию
  • поместить локальные петли в отдельные строки
...