记住一个以惰性序列作为输入的Clojure函数

时间:2016-07-31 15:07:29

标签: clojure

当memoised函数的参数是序列

时,如何记忆工作?
(defn foo
    ([x] (println "Hello First") (reduce + x))
    ([x y] (println "Hello Second") (reduce + (range x y))))


(def baz (memoize foo))

传递一个arg:

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个参数:

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"

1 个答案:

答案 0 :(得分: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在所有序列中以相同的方式工作。但“技术上”的工作并不意味着“有用”。正如您自己发现的那样,使用昂贵的比较语义输入是无用的(实际上甚至可能是有害的)。你的第二个签名解决了这个问题。