clojure - 懒惰序列内部实现

时间:2014-03-23 09:09:50

标签: clojure

我开始阅读/研究clojure,为此我开始并行阅读“Programming Clojure”和“Practical Clojure”书籍。我看到了一个例子,说明懒惰的序列工作对我来说非常清楚,以便了解laq-seq是如何工作的,但遗憾的是它不起作用或者至少不是我期望的。

这是一个例子:

(defn square[x]
  (do
   (println "[current.elem=" x "]")
   (* x x))
)

(def var-00 (map square '(1 2 3 5 6 4)))    

我打电话的时候:

var-00

,我希望在控制台(REPL)上没有要打印的消息,但我得到了以下结果:

([current.elem= 1 ][current.elem= 2 ]1 [current.elem= 3 ]4 [current.elem= 5 ]9  [current.elem= 6 ]25 [current.elem= 4 ]36 16)

这意味着函数映射被调用,即使我期望没有任何事情发生,因为'var-00'只是对函数'map'的引用;如果我打电话的话,从我的观点来看更加尴尬:

(nth var-00 2)

我得到了:

[current.elem= 1 ][current.elem= 2 ][current.elem= 3 ]9

,如果我再次打电话:

(nth var-00 3) 

我得到了:

[current.elem= 1 ][current.elem= 2 ][current.elem= 3 ][current.elem= 5 ]25; 

之前的元素(1,2,3)再次计算我认为这些元素应该通过第一次调用“缓存”,现在只应计算元素5。我做错了什么或者我没有完全理解懒惰序列在clojure中是如何工作的?提到我使用IntellijIDEA和LaClojure插件来运行程序。

谢谢索林。

2 个答案:

答案 0 :(得分:2)

刚刚在Clojure REPL检查了你的男女同校,这对我来说很好。每个元素只打印一次(第一次评估时)。

我甚至在Clojure online REPL中尝试了您的示例:

Clojure online REPL screenshot

但有一件事你错了。 REPL执行每个命令然后打印其结果,因此当您键入var-00 REPL解析符号然后,为了打印它,执行整个惰性序列:

Clojure online REPL screenshot

它与懒惰序列无关,它只是REPL的工作方式:

Clojure online REPL screenshot

答案 1 :(得分:-3)

懒惰评估并不意味着事情会被缓存。这意味着在计算中,只有在结果需要时才会评估元素。如果结果需要两次元素,则可能会对其进行两次评估。

如果你想要自动缓存元素,那么就有memoize函数,该函数将返回输入函数的转换版本,并添加了结果缓存。这也是实现动态编程的简便方法