事实上,它与对象分配有关。这是原始算法,带有注释:
(defn my-lcs [^objects a1 ^objects a2]
(first
(let [n (inc (alength a1))]
(areduce a1 i
;; destructuring of the initial value
[max-len ^ints prev ^ints curr]
;; initial value - a vector of [long int[] int[]]
[0 (int-array n) (int-array n)]
;; The return value: a vector with the prev and curr swapped positions.
[(areduce a2 j max-len (unchecked-long max-len) ;;
(let [match-len
(if (.equals (aget a1 i) (aget a2 j))
(unchecked-inc (aget prev j))
0)]
(aset curr (unchecked-inc j) match-len)
(if (> match-len max-len)
match-len
max-len)))
curr prev])))) ;; <= swaps prev and curr for the next iteration
根据 Java 版本,prev
并且被“重用” - 一种类似于此处描述curr
的动态编程方法。但是,这样做需要在每次迭代时分配一个新向量,然后将其传递给下一次归约。
通过将其放置在外部prev
并使其成为封闭对象的成员,他避免了在每次迭代中分配一个持久向量,而只是支付了装箱 a 的成本(甚至可能没有)。curr
areduce
^:unsynchronized-mutable
IFn
long
所以“丑陋”的把戏不在他的 Clojure 代码的先前迭代中,而是在 Java 版本中。