2013-05-09 84 views
1

我想知道为什么这个特定函数不能按预期工作。我怀疑从错误消息中可以看出,它与我为累加器创建空向量的方式有关。如何通过调用来构建矢量以减少

我有一个简单函数,返回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的方式来做我想做的事情,我也有兴趣听到这一点。

回答

2

问题可能出在accum-if-satisfies的else子句上,应该只是acc而不是(acc)

你可以使用filter然后map代替reduce。这样的:

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

你也可以拨打map-indexedvector,而不是(fn [i c] [i c])。 整个代码看起来像:

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

这正是问题。这么小的事情。我也喜欢你的版本。 – 2013-05-09 23:10:19

2

至于更Clojure的类似的方式,你可以使用

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

使用filter,而不是filterv返回一个懒惰的序列,而不是载体。

另外,您不应该使用defn来定义内部函数;它会在定义内部函数的命名空间中定义一个全局函数,并且除此之外还有微妙的副作用。使用letfn代替:

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

这个实现比我想要的要干净得多。我不知道嵌套的defn泄露到全局命名空间中。这是很好的信息。我假设了与Scala类似的范围规则。 – 2013-05-10 01:21:41

+2

'def *'形式根本不是用来引入本地绑定的; 'let'和'letfn'可用于此。 “def”的唯一目的是在当前命名空间中创建全局变量(其中“当前命名空间”是在编译时确定的)。 'defn','defmacro'等扩展到'def'。另外,那些'def'引入的全局变量是立即创建的,即使'def'形式被隐藏在一个函数体内,也就是说,尽管直到该代码被执行,它们才会得到绑定。 (当然有人可以在两个时间点之间来到Var并给出一个根绑定。) – 2013-05-10 01:45:18

1

另一种方式做到这一点是:

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