【问题标题】:Step-by-step example of a lazy-seq惰性序列的分步示例
【发布时间】:2012-11-23 21:49:24
【问题描述】:

我很难理解惰性工作以及缓存是如何工作的。

我认为工作中的惰性序列的分步示例可以在这里真正提供帮助。例如我读过以下问题:

Clojure lazy sequence usage

但还不清楚。

我的问题是调用如何确定另一个调用是否“等于”缓存调用以及它在缓存中保留多长时间?我试图 (source lazy-seq) 但显然它在 Java 领域,所以我在这里不走运。

对于一个简单的惰性序列,只取一个参数(比如说两个幂的列表),如果我用 5 和 8 调用它会怎样?只是这两个值被缓存了吗?

如果我要通过缓存已经调用惰性函数的每个输入来破坏内存,那么创建和缓存无限列表以获得无限结构的意义何在?

因为它说它会在每次后续调用时缓存结果...使用 's'。

1: 参数结果为 '1' 缓存 2: 参数结果为 '2' cached 3: 参数被 '3' 缓存的结果... 230: I 数到 230,这很好,因为我很懒惰,但现在 内存中有一个 2**30 缓存,缓存所有以前的所有调用 随后的调用。

还是只是缓存的最后一个调用?

如果我编写一个以树为参数的惰性函数会怎样?它是否在传递的参数上运行 equals? 以了解是否需要进行新的评估?

可以在运行时以某种方式跟踪这种行为吗?

【问题讨论】:

    标签: clojure equals lazy-evaluation


    【解决方案1】:

    惰性序列中的“缓存”不是一个可变缓存,它会像您在 web 应用程序中使用的那样过期,它是一个大小为 1 的缓存,列表中的每个单元格中都有一个。该“缓存”要么包含一个值,要么包含计算该值的代码,并且永远不会同时包含两者。一旦计算出该值,它就会缓存该值(在该单元格/条目中),如果有人再次读取该单元格,它会直接给他们该值,而不是调用代码。

    这里有一个简化的虚拟 repl 会话来说明这一点:

    user> (def a (range))
    a = [code-for-rest]
    user> (first a)
    a = [code-for-first, code-for-rest]
    a = [0, code-for-rest]
    result=> 0
    user> (first a)
    a = [0, code-for-rest]
    result=> 0
    user> (nth a 10)
    a = [0]->[1]->[2]->[3]->[4]->[5]->[6]->[7]->[8]->[9, code-for-rest]
    result=> 4
    

    在此示例中,每个单元格最初都包含(这是为了说明这一点而进行的简化)生成值的代码和生成列表其余部分的代码(如果这是列表的末尾,则为 nil) .一旦该单元被实现(变得不懒惰),它就会用实际值替换它的内容,所以它现在包含值和生成序列其余部分的代码。当读取列表中的下一个单元格时,它将首先由 code-for-rest(包含在单元格中)生成,然后新单元格中的 code-for-nth 将生成该单元格的值。

    【讨论】:

    • +1,非常感谢...如果“交织”调用惰性函数会发生什么情况(例如:“nth a 50”然后“nth a 100”然后“nth a 80”然后是“第一个 150”)?那么从不同线程对该函数的调用呢?每个线程都有一个大小为 1 的缓存吗?
    • @CedricMartin 惰性序列与所有其他 Clojure 数据结构一样,是不可变的,因此是线程安全的,因此一旦计算,存储的值就会在所有线程之间共享。将惰性 seq 视为指向链表的指针可能会有所帮助(这正是它的本质),只有链表的尾部在有人要求之前不会计算其下一个指针。
    • “缓存”实际上是在列表的单元格中。它没有附加到任何特定的线程。
    【解决方案2】:

    这里有一个展示运行时发生了什么的玩具示例:

    (defn times-two[number]
     (print "- ")
     (* 2 number))
    
    (def powers-of-two (lazy-cat [1 2] (map times-two (rest powers-of-two))))
    
    (println (take 10 powers-of-two))
    (println (take 12 powers-of-two))
    

    输出应该是:

    (1 - 2 - 4 - 8 - 16 - 32 - 64 - 128 - 256 512)

    (1 2 4 8 16 32 64 128 256 - 512 - 1024 2048)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-16
      • 2014-11-10
      • 2016-09-19
      • 1970-01-01
      • 2014-06-23
      • 2012-03-01
      • 2011-07-21
      • 2023-02-05
      相关资源
      最近更新 更多