Lazylist execute and #::: difference #::

Hi everbody,

The lazylist executes only if its needed otherwise its only there. input.take(idx) it takes an index at the indicated position but #::: why is this needed? input.drop it puts at that index. Can pls someone explain how this works?

def insert[T](input: LazyList[T], elem: T, idx: Int): LazyList[T] =

input.take(idx)#:::(elem#:: input.drop(idx))

Thanks,

take and drop work just like they do for List. They return new lists, containing all the elements up to resp. starting with the given index.

When you insert an element at index idx, it means that idx elements will be before it. input.take(idx) will return those, they’ll be the start of the new lazy list. In LazyList, take works lazily: the first element stays the same and the returned lazy list has its tail is set as tail.take(idx - 1), which is only evaluated, when accessing it.

All elements after the ones we get from take(idx) should come after the newly inserted elem. We get those with drop. To get to the current element at idx, drop(idx) has to evaluate all tails before that, but no further than idx.

So we have now the prefix input.take(idx) and the suffix input.drop(idx), and we want elem between them. As with non-lazy lists, prepending works better. So we prepend elem to the suffix with #::.
To join the two parts now, we need to use #:::. The variant with the three colons is for prepending another LazyList instead of an element.

If we’d use #:: here instead of #:::, the input.take(idx) part would become the first element of the new list, so it wouldn’t be a LazyList[T] anymore but a LazyList[Any] (containing both T and LazyList[T] elements).

1 Like

Wow crater2150 thanks a lot for explaining me the code!