Как построить вектор с помощью вызова, чтобы уменьшить

Я пытаюсь понять, почему эта функция не работает должным образом. Из сообщения об ошибке я подозреваю, что это как-то связано с тем, как я создаю пустой вектор для аккумулятора.

У меня есть простая функция, которая возвращает последовательность 2-элементных векторов:

(defn zip-with-index
  "Returns a sequence in which each element is of the
   form [i c] where i is the index of the element and c
   is the element at that index."
   [coll]
   (map-indexed (fn [i c] [i c]) coll))

Это отлично работает. Проблема возникает, когда я пытаюсь использовать его в другой функции

(defn indexes-satisfying
  "Returns a vector containing all indexes of coll that satisfy
   the predicate p."
  [p coll]
  (defn accum-if-satisfies [acc zipped]
    (let [idx (first zipped)
          elem (second zipped)]
      (if (p elem) 
        (conj acc idx)
        (acc))))
  (reduce accum-if-satisfies (vector) (zip-with-index coll)))

Он компилируется, но когда я пытаюсь его использовать, я получаю сообщение об ошибке:

user=> (indexes-satisfying (partial > 3) [1 3 5 7])
ArityException Wrong number of args (0) passed to: PersistentVector
clojure.lang.AFn.throwArity (AFn.java:437)

Я не могу понять, что здесь происходит. Также, если есть более "Clojure" способ сделать то, что я пытаюсь сделать, мне интересно услышать об этом тоже.

3 ответа

Решение

Проблема, вероятно, в другом предложении accum-if-satisfies, должно быть просто acc не (acc),

Вы могли бы использовать filter а потом map вместо reduce, Как это:

(map #(first %) 
     (filter #(p (second %))
             (zip-with-index coll)))

Вы также можете позвонить map-indexed с vector вместо (fn [i c] [i c]), Весь код будет выглядеть так:

(defn indexes-satisfying
  [p coll]
  (map #(first %)
       (filter #(p (second %))
               (map-indexed vector coll))))

Что касается более Clojure-подобного способа, вы можете использовать

(defn indexes-satisfying [pred coll]
  (filterv #(pred (nth coll %))
           (range (count coll))))

использование filter вместо filterv вернуть ленивый seq, а не вектор.

Кроме того, вы не должны использовать defn определить внутренние функции; вместо этого он будет определять глобальную функцию в пространстве имен, в которой определена внутренняя функция, и, кроме того, иметь незначительные побочные эффекты. использование letfn вместо:

(defn outer [& args]
  (letfn [(inner [& inner-args] ...)]
    (inner ...)))

Еще один способ сделать это будет:

(defn indexes-satisfying [p coll]
  (keep-indexed #(if (p %2) % nil) coll))
Другие вопросы по тегам