奇怪的减少Clojure中的行为

时间:2013-06-10 19:52:15

标签: function clojure reduce shadowing

编辑:这不是减少或减少功能的问题。我隐藏了clojure.core/range函数。

我有一个功能

(defn- roundfn [[xi ci bi oi :as state] r]
  (let [[xn cn bn] (newstate [xi ci bi] 0)
        exfn (word<-x xn)]
    [xn cn bn
     (into oi
           [(exfn [6 3 6 1])
            (exfn [4 1 4 7])
            (exfn [2 7 2 5])
            (exfn [0 5 0 3])])]))

其中x1,x2和x4本身就是向量。 x3是一个值。

当我减少此功能时

(reduce roundfn [[][] 0 []] (range 3))

(reduce roundfn [[][] 0 []] (vec (range 3)))

我收到了IndexOutOfBoundsException clojure.lang.PersistentVector.arrayFor (PersistentVector.java:107)

当我减少此功能时

(reduce roundfn [[][] 0 []] [0 1 2])

按预期工作

2 个答案:

答案 0 :(得分:2)

(正在处理this version of the source - 链接到该问题评论中提到的文件的当前版本。)

首先,在您列出的所有情况下,运行代码会在我的REPL中产生异常,包括文字[0 1 2]情况。如果事实并非如此,那将是惊人的。 (注意:我使用rabbit-round代替roundfn,因为这是在GitHub上的源代码中找到的问题文本中引用的函数的名称。)

问题的来源如下(根据问题评论中给出的完整来源的链接):

  1. 问题文本中列为roundfn的函数在源代码中称为rabbit-round。有问题的电话是(reduce rabbit-round [[] [] 0 []] [0 1 2])

  2. reduce比使用初始参数调用rabbit-round;其中发出了对roundfn的调用(roundfn是原始来源中的单独函数):(roundfn [[] [] 0] 0)。在这里抛出异常。

  3. roundfn是两个函数的组合;已经第一个成为问题的根源:(update-counter-system [[] [] 0] 0)抛出。

  4. 使用reduce作为缩减功能,在那里进行了进一步的counter-system-round调用。首次应用后者时抛出异常:(counter-system-round [[] 0] 0)

  5. 查看counter-system-round我们发现它尝试在第一行计算(nth c round)。此时,c绑定到[](空向量),round绑定为0。因此,此调用等于(nth [] 0)并正确抛出IndexOutOfBoundsException

答案 1 :(得分:0)

我用clojure.core\range解构

隐藏了[lower upper :as range]函数

以下是无效的版本

(generate-keystream [_ {:keys [ss] :as initmap} [lower upper :as range]]
  (let [ns (conj ss [])]
    (reduce rabbit-round ns (range 3))))

以下按预期方式工作(请注意更改为:as rng而不是:as range

(generate-keystream [_ {:keys [ss] :as initmap} [lower upper :as rng]]
  (let [ns (conj ss [])]
    (reduce rabbit-round ns (range 3))))

这解释了为什么(range 3)(vec (range 3))都不起作用,但[0 1 2]做了。前两个是在原始代码中评估([0 0] 3)(vec ([0 0] 3)),而[0 1 2]正在评估[0 1 2]并成功。

经验教训。不要影子功能

作为旁注,这也有效......

(generate-keystream [_ {:keys [ss] :as initmap} [lower upper :as range]]
  (let [ns (conj ss [])]
    (reduce rabbit-round ns (clojure.core/range 3))))