Я использую Scala 2.13.1 и оцениваю свои примеры на листе.
Сначала я определяю две функции, которые возвращают диапазон от a до (* 1005). * z -1) в виде потока или, соответственно, ленивого списка.
def streamRange(a: Int, z: Int): Stream[Int] = {
print(a + " ")
if (a >= z) Stream.empty else a #:: streamRange(a + 1, z)
}
def lazyListRange(a: Int, z: Int): LazyList[Int] = {
print(a + " ")
if (a >= z) LazyList.empty else a #:: lazyListRange(a + 1, z)
}
Затем я вызываю обе функции, беру Stream / LazyList из 3 элементов и преобразовываю их в список:
streamRange(1, 10).take(3).toList // prints 1 2 3
lazyListRange(1, 10).take(3).toList // prints 1 2 3 4
Здесь я снова делаю то же самое:
val stream1 = streamRange(1, 10) // prints 1
val stream2 = stream1.take(3)
stream2.toList // prints 2 3
val lazyList1 = lazyListRange(1,10) // prints 1
val lazyList2 = lazyList1.take(3)
lazyList2.toList // prints 2 3 4
1 печатается, потому что функция посещена, и оператор print находится в начале. Не удивительно.
Но я не понимаю, почему дополнительные 4 печатаются для ленивого списка, а не для потока.
Я предполагаю, что в точке, где 3 объединяется при следующем вызове функции версия LazyList посещает функцию, тогда как в версии Stream функция не посещается. В противном случае 4 не был бы напечатан.
Это кажется непреднамеренным поведением, по крайней мере, неожиданным. Но можно ли считать эту разницу в побочных эффектах ошибкой или просто детальной разницей в оценке Stream и LazyList.