如何通过调用reduce来构建向量

时间:2013-05-09 22:47:35

标签: exception vector clojure arity

我试图弄清楚为什么这个特殊功能没有按预期工作。我从错误消息中怀疑它与我为累加器创建空向量的方式有关。

我有一个简单的函数,它返回一个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 个答案:

答案 0 :(得分:2)

问题可能出在accum-if-satisfies的else子句中,应该只是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))))

答案 1 :(得分:2)

至于类似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 ...)))

答案 2 :(得分:1)

另一种方法是:

(defn indexes-satisfying [p coll]
  (keep-indexed #(if (p %2) % nil) coll))