【问题标题】:clojure - lazy sequence internal implementationclojure - 惰性序列内部实现
【发布时间】:2014-03-23 09:09:50
【问题描述】:

我开始阅读/研究 clojure,为此我开始同时阅读“Programming Clojure”和“Practical Clojure”书籍。我在那里看到了一个惰性序列如何工作的示例,对我来说非常清楚以了解惰性序列的工作原理,但不幸的是它不起作用,或者至少不是我期望的那样。

示例如下:

(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)

这意味着函数 map 被调用了,即使我认为不会发生任何事情,因为 '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; 

previous elements(1,2,3) 再次计算我认为这些元素应该在第一次调用时被“缓存”,现在只应该计算元素 5。我是不是做错了什么,或者我没有完全理解惰性序列在 clojure 中的工作原理?顺便提一下,我使用 IntellijIDEA 和 LaClojure 插件来运行程序。

谢谢索林。

【问题讨论】:

    标签: clojure


    【解决方案1】:

    刚刚在 Clojure REPL 中检查了你的 coed,它对我来说很好用。每个元素只打印一次(第一次评估时)。

    我什至在Clojure online REPL 中尝试过你的例子:

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

    它与惰性序列无关,它只是 REPL 的工作原理:

    【讨论】:

    • 谢谢,我的用于 clojures 的 Intellij 插件无法正常工作。
    【解决方案2】:

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

    如果您想自动缓存元素,可以使用 memoize 函数,该函数将返回输入函数的转换版本,并添加了结果缓存。这也是实现动态规划的简便方法

    【讨论】:

    • 好吧,那是错误的。惰性序列的元素实际上只在需要时才被评估它们不会在每次访问时都被评估。只需在您当地的 Leiningen REPL 中尝试 OP 的示例,您只会看到一次输出。
    猜你喜欢
    • 2011-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-04
    • 2011-06-26
    • 2010-12-08
    • 2014-06-17
    相关资源
    最近更新 更多