5

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

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

Clojure 惰性序列用法

但目前还不清楚。

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

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

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

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

1: 参数结果为 '1' 缓存 2: 参数结果为 '2' 缓存 3: 参数结果为 '3' 缓存... 2 30: 我数到了 2 30 这很棒因为我很懒和所有,但现在内存中有一个 2**30 缓存,用于缓存所有后续调用的所有先前调用。

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

如果我编写一个以树为参数的惰性函数怎么办?它运行等于吗?关于通过的论点知道是否需要进行新的评估?

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

4

2 回答 2

8

惰性序列中的“缓存”不是一个可变缓存,它会像您在 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 将生成该单元格的值。

于 2012-12-05T23:04:06.543 回答
1

这里有一个玩具示例,显示了运行时发生的情况:

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

于 2012-12-06T02:22:59.663 回答