序列与 LazyList
我无法理解序列和 LazyList 之间的差异。他们都很懒惰,而且潜力无限。虽然 seq<'T>
是 .NET 框架中的 IEnumerable<'T>
,但 LazyList
包含在 F# PowerPack。在实践中,我遇到的序列比 LazyList 更频繁。
它们在性能、使用、可读性等方面有何差异?与 seq
相比,LazyList
的声誉如此差的原因是什么?
I can't wrap my head around the differences between sequence and LazyList
. They're both lazy and potentially infinite. While seq<'T>
is IEnumerable<'T>
from .NET framework, LazyList
is included in F# PowerPack. In practice, I encounter sequences much more often than LazyList
s.
What are their differences in terms of performance, usage, readability, etc? What are reasons for such a bad reputation of LazyList
compared to that of seq
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
无论遍历列表多少次,
LazyList
都只计算每个元素一次。这样,它更接近于从Seq.cache
返回的序列(而不是典型的序列)。但是,除了缓存之外,LazyList 的行为与列表完全相同:它在底层使用列表结构并支持模式匹配。因此,您可能会说:当您需要列表语义和缓存(除了惰性之外)时,请使用LazyList
而不是seq
。关于两者都是无限的,
seq
的内存使用量是恒定的,而LazyList
的内存使用量是线性的。这些文档可能值得一读。
LazyList
computes each element only once regardless of how many times the list is traversed. In this way, it's closer to a sequence returned fromSeq.cache
(rather than a typical sequence). But, other than caching,LazyList
behaves exactly like a list: it uses a list structure under the hood and supports pattern matching. So you might say: useLazyList
instead ofseq
when you need list semantics and caching (in addition to laziness).Regarding both being infinite,
seq
's memory usage is constant whileLazyList
's is linear.These docs may be worth a read.
除了丹尼尔的回答之外,我认为主要的实际区别在于如何处理
LazyList
或seq
结构(或计算)。如果您想要处理
LazyList
,通常会使用模式匹配编写递归函数(与处理普通 F# 列表非常相似)如果您想处理
seq
,您可以使用内置函数或者你必须写命令式调用 GetEnumerator 的代码,然后在循环中使用返回的枚举器(可以编写为递归函数,但它会改变枚举器)。您不能使用通常的头/尾样式(使用Seq.tail
和Seq.head
),因为那效率极低 - 因为seq
确实不保留求值的元素,Seq.head
的结果需要从头开始重新迭代。关于 seq 和 LazyList 的声誉,我认为 F# 库设计采取了务实的方法 - 因为 seq 实际上是 .NET IEnumerable ,对于 .NET 编程来说非常方便(而且它也很好,因为您可以将其他集合视为
seq
)。惰性列表并不常见,因此普通的 F# 列表和 seq 在大多数情况下就足够了。In addition to Daniel's answer, I think the main practical difference is how you process the
LazyList
orseq
structures (or computations).If you want to process
LazyList
, you would typically write a recursive function using pattern matching (quite similar to processing of normal F# lists)If you want to process
seq
, you can either use built-in functions or you have to write imperative code that callsGetEnumerator
and then uses the returned enumerator in a loop (which may be written as a recursive function, but it will mutate the enumerator). You cannot use the usual head/tail style (usingSeq.tail
andSeq.head
), because that is extremely inefficient - becauseseq
does not keep the evaluated elements and the result ofSeq.head
needs to re-iterate from the start.Regarding the reputation of
seq
andLazyList
, I think that F# library design takes a pragmatic approach - sinceseq
is actually .NETIEnumerable
, it is quite convenient for .NET programming (and it is also nice because you can treat other collections asseq
). Lazy lists are not as frequent and so normal F# list andseq
are sufficient in most of the scenarios.