2

假设我有一个无副作用的函数,我重复使用相同的参数而不将结果存储在变量中。Clojure 是否注意到这一点并使用函数的预先计算的值,还是一直重新计算该值?

例子:

(defn rank-selection [population fitness]
  (map
    #(select-with-probability (sort-by fitness population) %)
    (repeatedly (count population) #(rand))))

(defn rank-selection [population fitness]
  (let [sorted-population (sort-by fitness population)]
    (map
      #(select-with-probability sorted-population %)
      (repeatedly (count population) #(rand)))))

在第一个版本sort-by中执行n-times(n人口规模在哪里)。在第二个版本sort-by中执行一次,结果使用n-times

Clojure 是否仍然存储结果?这些方法比较快吗?

4

2 回答 2

1

在 Clojure 中,序列是惰性的,但语言的其余部分,包括函数求值,是急切的。Clojure 每次都会为您调用该函数。使用排名选择功能的第二个版本。

于 2013-06-10T15:52:00.300 回答
1

除非您在代码中指定,否则 Clojure 不会存储结果,或者通过使用memoize注释中提到的方法,或者像您一样将计算/结果保存在本地绑定中。

关于一个函数相对于另一个函数有多快的问题,这里有一些代码返回每个函数的执行时间(我不得不模拟这个select-with-probability函数)。doalls 是强制评估 的结果所必需的map

(defn select-with-probability [x p]
  (when (< p 0.5)
    x))

(defn rank-selection [population fitness]
  (map
    #(select-with-probability (sort-by fitness population) %)
    (repeatedly (count population) rand)))

(defn rank-selection-let [population fitness]
  (let [sorted-population (sort-by fitness population)]
    (map
      #(select-with-probability sorted-population %)
      (repeatedly (count population) rand))))
      
(let [population (take 1000 (repeatedly #(rand-int 10)))]
  (time (doall (rank-selection population <)))
  (time (doall (rank-selection-let population <)))
  ;; So that we don't get the result seq
  nil)

这将在我的本地环境中返回以下内容:

"Elapsed time: 95.700138 msecs"
"Elapsed time: 1.477563 msecs"
nil

编辑

为了避免使用let表单,您还可以使用partial它接收一个函数和任意数量的参数,并使用提供的参数值返回该函数的部分应用程序。生成的代码的性能与带有表单的代码的顺序相同,let但更简洁易读。

(defn rank-selection-partial [population fitness]
  (map
    (partial select-with-probability (sort-by fitness population))
    (repeatedly (count population) rand)))

(let [population (take 1000 (repeatedly #(rand-int 10)))]
  (time (doall (rank-selection-partial population <)))  
  ;; So that we don't get the result seq
  nil)

;= "Elapsed time: 0.964413 msecs"
于 2013-06-10T16:36:55.757 回答