2012-02-08 33 views
16

我無法圍繞序列和LazyList之間的差異。他們既懶惰又潛力無限。而來自.NET框架的seq<'T>IEnumerable<'T>,包含在F# PowerPack中。在實踐中,我比LazyList更頻繁地遇到序列。序列與LazyList

它們在性能,用法,可讀性等方面有什麼不同?與seq相比,LazyList的聲譽如此差的原因是什麼?

回答

31

LazyList無論列表遍歷多少次,每個元素只計算一次。通過這種方式,它更接近從Seq.cache返回的序列(而不是典型的序列)。但是,除了緩存之外,LazyList的行爲與列表完全相同:它在引擎蓋下使用列表結構並支持模式匹配。所以你可能會說:當你需要列表語義和緩存(除了懶惰之外)時,可以使用LazyList而不是seq

關於兩者都是無限的,seq的內存使用率是恆定的,而LazyList的是線性的。

這些docs可能值得一讀。

+0

+1,很酷,我不知道緩存部分。你能舉一個需要懶惰和列表語義的例子嗎? – pad 2012-02-08 21:19:25

+0

遍歷一個序列,同時訪問多個元素可以使用'seq'來完成,但是使用'LazyList' +模式匹配更加簡潔。 – Daniel 2012-02-08 21:21:36

+0

參見例如http://stackoverflow.com/questions/3484315/how-to-merge-sorted-sequences-in-f和http://stackoverflow.com/questions/1306140/f-why-is-using-a-sequence-如此慢得多使用列表中的這個例子/ 1306267#1306267 – Brian 2012-02-08 21:27:33

19

除了丹尼爾的回答,我認爲主要的實際區別是你如何處理LazyListseq結構(或計算)。

  • 如果你要處理LazyList,您通常會使用模式匹配(非常類似於普通F#列表的處理)

  • 如果你要處理seq,您可以用寫一個遞歸函數內置函數,或者你必須編寫調用GetEnumerator的命令式代碼,然後在循環中使用返回的枚舉器(可以將其寫成遞歸函數,但它會改變枚舉器)。您不能使用通常的頭/尾樣式(使用Seq.tailSeq.head),因爲這樣效率極低 - 因爲seq不保留評估的元素,並且Seq.head的結果需要從頭開始重新迭代。

關於seqLazyList聲譽,我認爲F#庫設計採取務實的態度 - 因爲seq實際上是.NET IEnumerable,它是.NET編程比較方便(它也是因爲你好看可以將其他收藏品視爲seq)。懶惰列表並不常見,因此在大多數情況下,正常的F#列表和seq就足夠了。