2012-02-08 2 views
16

Я не могу обернуть голову вокруг различий между последовательностью и LazyList. Они ленивы и потенциально бесконечны. В то время как seq<'T> является IEnumerable<'T> из .NET framework, LazyList включен в F# PowerPack. На практике я встречаю последовательности гораздо чаще, чем LazyList с.Последовательность против LazyList

В чем их отличие в плане производительности, использования, удобочитаемости и т. Д.? Каковы причины такой плохой репутации LazyList по сравнению с seq?

ответ

31

LazyList вычисляет каждый элемент только один раз, независимо от того, сколько раз перебирается список. Таким образом, он ближе к последовательности, возвращенной из Seq.cache (а не к типичной последовательности). Но, кроме кэширования, LazyList ведет себя точно так же, как и список: он использует структуру списка под капотом и поддерживает сопоставление шаблонов. Поэтому вы можете сказать: используйте LazyList вместо seq, когда вам нужна семантика списка и кеширование (в дополнение к лени).

Относительно того, что оба являются бесконечными, использование памяти памяти seq является постоянным, а LazyList является линейным.

Возможно, это docs.

+0

+1, круто, я не знал о кешировании части. Не могли бы вы привести пример, который требует как лености, так и семантики списка? – pad

+0

Перемещение последовательности при одновременном доступе к нескольким элементам может быть выполнено с помощью 'seq', но оно намного более чистое с использованием сопоставления с образцом LazyList +. – Daniel

+0

См., Например, http://stackoverflow.com/questions/3484315/how-to-merge-sorted-sequences-in-f и http://stackoverflow.com/questions/1306140/f-why-is-using-a-sequence- so-much-slower-than-using-a-list-in-this-example/1306267 # 1306267 – Brian

19

В дополнение к ответу Даниэля, я думаю, что основная практическая разница заключается в том, как вы обрабатываете структуры (или вычисления) LazyList или seq.

  • Если вы хотите обработать LazyList, то, как правило, написать рекурсивную функцию, используя поиск по шаблону (весьма похожий на обработку нормальных F списков #)

  • Если вы хотите обработать seq, вы можете использовать встроенные функции, или вам нужно написать императивный код, который вызывает GetEnumerator, а затем использует возвращенный перечислитель в цикле (который может быть записан как рекурсивная функция, но он будет мутировать перечислитель). Вы не можете использовать обычный стиль головы/хвоста (используя Seq.tail и Seq.head), потому что это крайне неэффективно, потому что seq не сохраняет оцененные элементы, а результат Seq.head требует повторной итерации с самого начала.

Что касается репутации seq и LazyList, я думаю, что дизайн F # библиотека принимает прагматический подход - с seq на самом деле .NET IEnumerable, это очень удобно для .NET программирования (и это тоже хорошо, потому что вы может обрабатывать другие коллекции как seq). Ленивые списки не так часто встречаются, и поэтому нормальный список F # и seq достаточны в большинстве сценариев.

Смежные вопросы