【问题标题】:Sequence vs LazyList序列与惰性列表
【发布时间】:2012-03-01 08:45:58
【问题描述】:

我无法理解序列和LazyList 之间的差异。他们既懒惰又可能是无限的。虽然seq<'T> 是来自.NET 框架的IEnumerable<'T>,但LazyList 包含在F# PowerPack 中。在实践中,我比LazyLists 更频繁地遇到序列。

它们在性能、使用、可读性等方面有何不同?与seq相比,LazyList的名声如此糟糕的原因是什么?

【问题讨论】:

    标签: data-structures f# sequence lazy-evaluation


    【解决方案1】:

    LazyList 只计算每个元素一次,无论列表被遍历多少次。这样,它更接近于从Seq.cache 返回的序列(而不是典型的序列)。但是,除了缓存之外,LazyList 的行为与列表完全一样:它在底层使用列表结构并支持模式匹配。所以你可能会说:当你需要列表语义和缓存(除了惰性)时,使用LazyList 而不是seq

    关于两者都是无限的,seq 的内存使用是恒定的,而LazyList 是线性的。

    这些docs 可能值得一读。

    【讨论】:

    • +1,很酷,我不知道缓存部分。你能举一个同时需要惰性和列表语义的例子吗?
    • 使用seq 可以在同时访问多个元素的同时遍历一个序列,但是使用LazyList + 模式匹配会更简洁。
    • @pad:我添加了指向 MSR 上旧文档的链接。它很好地解释了它们。
    • 这里提到的缓存如何与在 Haskell 世界中的记忆化相比,记忆化意味着一旦计算出一个值,如果将来需要,它会被保存并再次使用?
    【解决方案2】:

    除了 Daniel 的回答之外,我认为主要的实际区别在于您如何处理 LazyListseq 结构(或计算)。

    • 如果要处理LazyList,通常会使用模式匹配编写递归函数(非常类似于处理普通 F# 列表)

    • 如果要处理seq,可以使用内置函数,也可以编写命令式代码调用GetEnumerator,然后在循环中使用返回的枚举数(可以写成一个递归函数,但它会改变枚举数)。您不能使用通常的头/尾样式(使用Seq.tailSeq.head),因为那是非常低效的 - 因为seq 不保留评估的元素并且Seq.head 的结果需要从开始。

    关于seqLazyList的名声,我认为F#库设计采取务实的态度——因为seq实际上是.NETIEnumerable,对于.NET编程来说是相当方便的(而且它是也很好,因为您可以将其他集合视为seq)。惰性列表没有那么频繁,所以普通的 F# 列表和seq 在大多数情况下就足够了。

    【讨论】:

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