2016-07-31 29 views
1

当参数传递给一个memoised功能是一个序列memoize的一个Clojure的函数,它接受一个懒惰的顺序输入

(defn foo 
    ([x] (println "Hello First") (reduce + x)) 
    ([x y] (println "Hello Second") (reduce + (range x y)))) 


(def baz (memoize foo)) 

传递一个ARG怎样才可以有memoize的工作:

1)

(time (baz (range 1 1000000))) ;=> Hello First "Elapsed time: 14.870628 msecs" 

2)

(time (baz (range 1 1000000))) ;=> "Elapsed time: 65.386561 msecs" 

传递2个ARGS:

1)

(time (baz 1 1000000)) ;=> Hello Second "Elapsed time: 18.619768 msecs" 

2)

(time (baz 1 1000000)) ;=> "Elapsed time: 0.069684 msecs" 

当传递2个参数的函数的第二次运行似乎是我所期望的。

但是使用矢量的工作原理。

(time (baz [1 2 3 5 3 5 7 4 6 7 4 45 6 7])) ;=> Hello First "Elapsed time: 0.294963 msecs" 


(time (baz [1 2 3 5 3 5 7 4 6 7 4 45 6 7])) ;=> "Elapsed time: 0.068229 msecs" 
+0

嗯。如何处理这是一件棘手的事情 - 需要消耗整个序列来确定用于比较的身份,但能够支持ISeq的优势之一是潜在的懒惰。所以我可以看到当前语义的争论 - 我们不希望增加调用的前期成本(为了充分实现理论上可能无限的序列),以便可能启用缓存。 –

+0

...在实现层,问题是当序列被用作映射中的键时会发生什么。即。 do序列以反映其内容(因此需要评估的O(n))的方式支持'.hashCode',以反映它们的身份(使得相同的序列仅与其自身比较)或者根本不? –

+0

@CharlesDuffy - 序列比较(散列码等)的任何实现都只能优化不等式的情况。当'memoize'被设计为有用的时候 - 当你在地图上有相同的关键字时 - 如此矛盾地正确 - 你会以O(n)比较时间结束,不管实现是什么。故事的寓意 - “memoize”不是用于长序列作为参数。 –

回答

3

memoize确实与序列工作,你只需要比较苹果苹果。 memoize在先前使用的哈希映射中查找参数,并最终比较序列。比较长的序列是什么需要很长的时间,无论是矢量与否:

user> (def x (vec (range 1000000))) 
;; => #'user/x 
user> (def y (vec (range 1000000))) 
;; => #'user/y 
user> (time (= x y)) 
"Elapsed time: 64.351274 msecs" 
;; => true 
user> (time (baz x)) 
"Elapsed time: 67.42694 msecs" 
;; => 499999500000 
user> (time (baz x)) 
"Elapsed time: 73.231174 msecs" 
;; => 499999500000 

当您使用很短的输入序列,定时由你的函数内reduce为主。但是很长一段时间你看到的实际上是memoize内的比较时间。

所以在技术上memoize的作品,以同样的方式对所有的序列。但是“技术性”工作并不意味着“有用”。正如你自己发现的那样,用昂贵的比较语义进行输入是没有用的(实际上甚至可能是有害的)。你的第二个签名解决了这个问题。

相关问题