Последовательность против LazyList

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

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

Ответы

Ответ 1

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

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

Эти docs могут быть полезны для чтения.

Ответ 2

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

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

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

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