Последовательность против 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
достаточны в большинстве сценариев.