This module defines utility functions and augmentations to ease the use of
the `gololang.LazyList`

object.

A lazy list is an *immutable* list whose elements are evaluated only when needed,
as can be found in Haskell for example.

This is very useful when using higher order function such as `map`

. Mapping
a long lazy list with a function and using only the 3 first elements will only
apply the function to these elements, as opposed to regular lists.

Lazy lists can also be used to create infinite lists, also known as generators (or anamorphisms).

Lastly, they allow for elegant recursive implementations of several classical algorithms.

For instance, one can create a infinite lazy list containing integers as:

```
function count = |start| -> cons(start, -> count(start + 1_L))
function count = -> count(0_L)
```

On the other hand, functions or methods like `equals`

, `size`

or `contains`

are
not very efficients, since they must evaluate the whole list, and thus negate
the laziness. They are here for completeness and compatibility with the regular
lists interface, but you should avoid such methods.

Some functions in this module are recursive (re)implementation of standard list
HOF, such as `map`

or `filter`

. The recursive aspect should not be limiting since
the resulting list is lazy.

null

Remove `nb`

elements from the list and return the rest as a lazy list.

Remove elements from the list as long as the given predicate is true.

`pred`

: the predicate function used to end the list.

Filters elements based on a predicate.

Returns a new lazy list.

Finds the first element of a list matching a predicate:

```
println(lazyList(1, 2, 3, 4): find(|n| -> n > 3))
```

`this`

: a lazy list.`pred`

: a predicate function taking an element and returning a boolean.

`find`

returns `null`

when no element satisfies `pred`

.

Note that in the worst case, all the list is search. Take care to **not use**
this method on infinite list, since no check is made.

Folds left `this`

using `func`

with `zero`

as initial value.
This is a recursive implementation.

```
lazyList(a, b, c): foldl(f, z) == f(f(f(z, a), b), c)
```

Equivalent to `foldr`

if `func`

is commutative.

Folds right `this`

using `func`

with `zero`

as initial value.
This is a recursive implementation.

```
lazyList(a, b, c): foldr(f, z) == f(a, f(b, f(c, z)))
```

Equivalent to `foldl`

if `func`

is commutative.

Joins the elements into a string:

```
println(list[1, 2, 3]: join(", "))
```

`this`

: a list.`separator`

: the element separator string.

The returned string is `""`

when the list is empty.

Maps elements of a list using a function:

```
lazyList(1, 2, 3):map(|x| -> 2 * x)
```

`map`

returns a new lazy list, i.e. `func`

is applied only
when necessary.

This is a recursive implementation.

Extract a lazy sublist.

This is just a convenient method for `list: drop(from):take(to - from)`

, so
the list remains lazy.

`from`

: low endpoint (inclusive) of the`subList`

`to`

: high endpoint (exclusive) of the`subList`

Takes the `nb`

first elements of the lazy list, as a lazy list.
This is a wrapper, the underlying list is resolved on demand, such that
everything remains lazy. `take`

can thus be used on infinite lists.

Takes elements from the list as long as the given predicate is true.

`pred`

: the predicate function used to end the list.

null

Returns a lazy list from this `Iterable`

. Can be used for instance to lazily
map a list.

null

Returns a lazy list view of this `Iterator`

.

Unary version of `cons(head, tail)`

.

Its parameter is assumed to be a tuple (or any object having a `get(idx)`

method)
of the form `[head, tail]`

.

Create a new lazy list from a head and tail values. Automatically wraps the tail in a closure if its not already one.

For example:

```
let myList = cons(1, cons(2, cons(3, emptyList())))
```

gives a lazy list equivalent to `list[1, 2, 3]`

Returns the empty list.

Wraps any object implementing `Iterable`

or `Iterator`

in a lazy list.
The `next()`

method of the underlying iterator is only called when the tail is
used.

NOTE:
If called with an `Iterator`

instance, the iterator is shared, so navigating
through the list can have side effects if another object is using the same
iterator.

Generator function on lazy lists (anamorphism).

This function generates a (possibly infinite) lazy list. Starting with the
`seed`

value, if `finished(seed)`

is `true`

, the generation stops and an empty
list is returned. Otherwise, `unspool`

is called on `seed`

, and must generate
two values: the head of the list (current value) and the next seed that will be
used to generate the tail.

As an example, one can write a simple `range`

function as:

```
let range = |start, end| -> generator(
|seed| -> [seed, seed + 1],
|seed| -> seed >= end,
start
)
```

`unspool`

: the generative function`finished`

: the condition function`seed`

: the initial value

Returns an infinite lazy list produced by iterative application of a function
to an initial element.
`iterate(z, f)`

thus yields `z, f(z), f(f(z)), ...`

For instance, one can create a infinite list of integers using:

```
iterate(0, |x| -> x + 1)
```

`zero`

: the initial element of the list`func`

: the function to apply

Variadic function to create lazy lists from values.

```
let myList = lazyList(1, 2, 3, 4)
```

is the equivalent to

```
let myList = cons(1, cons(2, cons(3, cons(4, emptyList()))))
```

Produces a infinite list of values. If the argument is a closure, it must have
no parameters, and it's used to produce the values (called for each `tail`

access).

For instance, `repeat(5)`

will return an infinite lazy list of `5`

s, and
`repeat(^f)`

will return a infinite lazy list of calls to `f`

([f(), f(), f(), …])

`value`

: a value or a closure