2

I am just trying the new kotlin language. I came across sequences which generate infinite list. I generated a sequence and tried printing the first 10 elements. But the below code didnt print anything:

fun main(args: Array<String>) {
    val generatePrimeFrom2 = generateSequence(3){ it + 2 }
    print(generatePrimeFrom2.toList().take(10))
}

But when I changed take(10).toList() in the print statement it work fine. Why is it so ?

This code worked fine for me:

fun main(args: Array<String>) {
    val generatePrimeFrom2 = generateSequence(3){ it + 2 }
    print(generatePrimeFrom2.take(10).toList())
}
sagar suri
  • 4,351
  • 12
  • 59
  • 122

4 Answers4

8

The generateSequence function generates a sequence that is either infinite or finishes when the lambda passed to it returns null. In your case, it is { it + 2 }, which never returns null, so the sequence is infinite.

When you call .toList() on a sequence, it will try to collect all sequence elements and thus will never stop if the sequence is infinite (unless the index overflows or an out-of-memory error happens), so it does not print anything because it does not finish.

In the second case, on contrary, you limit the number of elements in the sequence with .take(10) before trying to collect its items. Then the .toList() call simply collects the 10 items and finishes.

It may become more clear if you check this Q&A about differences between Sequence<T> and Iterable<T>: (link)

hotkey
  • 140,743
  • 39
  • 371
  • 326
  • Yeah you are right. I think IDE should hint me that `toList().take(10) will be infinite` when I do this on a sequence – sagar suri Feb 07 '18 at 12:53
5

Here is the hint -> generate infinite list. In the first solution you first want to create a list (wait infinity) then take first 10 elements.

On the second snippet, from infinite list you take only first 10 elements and change it to list

pezetem
  • 2,503
  • 2
  • 20
  • 38
1

generatePrimeFrom2.toList() tries to compute/create an infinite-length list.
generatePrimeFrom2.toList().take(10) then takes the first 10 elements from the infinite-length list.
It does not print because it is calculating that infinite-length list.

Whereas, generatePrimeFrom2.take(10) only tries to compute the first 10 elements. generatePrimeFrom2.take(10).toList() converts the first 10 elements to the list.

You know, generateSequence(3){ it + 2 } does not have the end. So it has the infinite length.
Sequences do not have actual values, calculated when they are needed, but Lists have to have actual values.

Naetmul
  • 14,544
  • 8
  • 57
  • 81
  • Yeah you are right. I think IDE should hint me that `toList().take(10) will be infinite` when I do this on a sequence. – sagar suri Feb 07 '18 at 12:52
1

I came across sequences which generate infinite list.

This is not actually correct. The main point is that a sequence is not a list. It is a lazily evaluated construct and only the items you request will actually become "materialized", i.e., their memory allocated on the heap.

That's why it's not interchangeable to write

infiniteSeq.toList().take(10)

and

infiniteSeq.take(10).toList()

The former will try to instantiate infinitely many items—and, predictably, fail at it.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436