Question

EDIT: This was not a problem with reduce or the function being reduced. I shadowed the clojure.core/range function.

I have a function

(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])])]))

where x1,x2, and x4 are themselves vectors. x3 is a value.

When I reduce this function like

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

or

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

I'm receiving IndexOutOfBoundsException clojure.lang.PersistentVector.arrayFor (PersistentVector.java:107)

When I reduce this function like

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

it works as expected

Was it helpful?

Solution 2

I was shadowing the clojure.core\range function with my [lower upper :as range] destructuring

Below is the version that didn't work

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

The following works as expected (note the change to :as rng instead of :as range)

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

This explains why (range 3) and (vec (range 3)) both didn't work, but [0 1 2] did. The first two were evaluating to ([0 0] 3) and (vec ([0 0] 3)) in my original code, while [0 1 2] was evaluating to [0 1 2] and succeeding.

Lesson learned. Don't shadow functions

As a side note, this works too...

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

OTHER TIPS

(Working off of this version of the source -- link to the current revision of the file mentioned in a comment on the question.)

Firstly, running your code produces the exception at my REPL in all the cases you listed, including the literal [0 1 2] case. It would be astounding if this were not the case. (NB. I use rabbit-round in place of roundfn, since that's the name of the function quoted in the question text as found in the source on GitHub.)

The problem's source is as follows (based on the link to the full source given in a comment on the question):

  1. The function listed as roundfn in the question text is called rabbit-round in the source. The problematic call is (reduce rabbit-round [[] [] 0 []] [0 1 2]).

  2. The reduce than calls rabbit-round with the initial arguments; therein a call to roundfn takes place (roundfn being a separate function in the original source): (roundfn [[] [] 0] 0). It is here that the exception gets thrown.

  3. roundfn is a composition of two functions; already the first turns out to be the source of the problem: (update-counter-system [[] [] 0] 0) throws.

  4. There's a further reduce call in there using counter-system-round as the reduction function. The exception is thrown when the latter is first applied: (counter-system-round [[] 0] 0).

  5. Looking at counter-system-round we see that it attempts to compute (nth c round) in the first line. At this point, c is bound to [] (an empty vector) and round will be 0. Thus this call amounts to (nth [] 0) and correctly throws IndexOutOfBoundsException.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top