The laziness of generators is a great property.
Published: 2023-11-26 18:24:23

I won't describe what are generators, many people will do it way better than I could.

Here is a very good documentation [JSINFO](https://javascript.info/generators)

You know now what they are, 
Time to explore their laziness property.

Let's first create two generators functions (thanks to James Sinclair):

```js
function* filter(p, xs) {
  for (const x of xs) if (p(x)) yield x;
}

function* map(fn ,xs) {
   for (const x of xs) yield fn(x)
}

```

Testing their laziness :

```js

let data = [1,2,3,4,5,7,8,9,10]

let evens = filter(x => x % 2 == 0, data);

console.log(evens) // empty array

```
The result of our **filter** function is an empty array !!!

The rule is that a generator does not produce any value until you really iterate on it.

Let's try the following :

```js

let data = [1,2,3,4,5,7,8,9,10]

let evens = filter(x => x % 2 == 0, data);

console.log(Array.from(evens)) // [ 2, 4, 8, 10 ]

```
This time we get an actual value, great.

It would be nicer if we could wrote :

```js

let results = evens.toArray ()

```
This method does not exists on generators, so let's create an extension method, to allow it :

```js

Object.defineProperty(
 Object.getPrototypeOf(function* () {}).prototype,
 "toArray",
 {
   value: function () { return Array.from(this) }
 }
);

```

Let's try it :

```js

let data = [1,2,3,4,5,7,8,9,10]

let evens = filter(x => x % 2 == 0, data);

console.log(evens.toArray()) // [ 2, 4, 8, 10 ]

```

Great, that works.

Recall, until we are not applying our **toArray** extension, nothing is evaluated, executed, generators are lazy by nature.

Let's go a little further :

Given this array :

```js

const data = [1,2,4,5,6,7,8,9,10]

```

Let's return the even values greater than 4 and multiplied by 5:

```js

let evens = filter(x => x % 2 == 0, data);

let evensSup4 = filter(x => x > 4, evens);

let mul5evensSup4 =  map(x => x * 5, evensSup4);

```

[demo](https://flems.io/#0=N4IgZglgNgpgziAXAbVAOwIYFsZJAOgAsAXLKEAGhAGMB7NYmBvEAXwvW10QICsEqdBk2J4wAVzTViEegCoABJCiMATgAoADhQUAPOAEoFwADpoFS2qoXqhcYnoW0wewwogut63QaMBPCBgoABM9AG4zVjMzCSkZeQUsDE11MHMKfSNTcwswKxs7B10nF0yFAKDQtO8DSOi0AHkAI14YaXxgmEg0GAAFVVpNGFViP3UzBWbW9oBzGGJ+2mIlvyGGsFTJaVk0RXUs1gN8TQHl0aGKCZMQZYBBVVUMP2vL82yLBQA3DChxGEQlFt4uZ9sYFKp5uJVOZ7o8-PgwAMsOpiIQIG4ouZMQYImgzLAHMEMMQMAoALwKZAARh0ACYdABmHQAFh0AFYdAA2HQAdh0AA4dABOHRUgAMAF16gSFDBPkw4OSlNA1N5yQA+CzABR2WiwfBQWgzcYgTQYCCqCBoGbXIxhCHEKHmYoAUgUtPJFLFCnYCiJJJx0vmsvlaDgAGVxJpmUrlKrimTNcZdfrDcbrnAo8zbWFwZDoRZipqY765QrA3i0DKsOIoGyy2HI9GlYlkupHImtTr6HA9TADUaTTW6zm846C8VFGzS6GI1mK2YAPSLhQAFWgUAUqKYCjQSzR1tluja4kYwXw9RT-bT6mH9dnTeZBkoIDgQTawIQPFpnMQP7YHAgJgOB4Pg1BwAIND0IwzA8GwEqsEAA)

Note, that our functions are provided with actual data, and nothing is executed, awesome !!!

Time to unveil the results :

We can pass the generator with 'its' context to a function.

```js

function showMul5Evens (gen) {
  console.log(gen.toArray())
}

showMul5Evens(mul5evens) // [ 30, 40, 50 ]

```

[Demo](https://flems.io/#0=N4IgtglgJlA2CmIBcB2AjAOgGwBYA0IAZhAgM7IDaoAdgIZiJIgYAWALmLCAQMYD21NvEHIQIAL54a9RswBW5XgKEimhAK7UebCAIBUAAmKwhAJwAUABzwGAHqQCUB4AB1qBo31MHz-aqTY7Az5CO0cDCFCrc1sHJwBPCHhYKDsAbjdxNzcNLR19AzBaS3NCdzx7J1d3D0IvHz8AoJCwhKSUo2oYh0zs6gB5ACM5eG0MKHhiangABVM+S3hTNnjzNwMhkbGAc3g2Ob42Q-jF-sJSzW1dakNzKvEHDEt5o5XFvHWXECOAQVNTWjxL4fdzVDwGAButFg6ngSCMl3y7juzgMpj26lM7j+APiGEI8zA5jYLAg4Sy7gpDgy1DcCECUFobFoBgAvAYKGgbAAmGwAZhs+AMAFYbFgbCgbAAOGwAThsaAADABdPr0gzwCHCUhsowkMwxNkAPiCAFIDNy2ezFTZGczqWq9hqtf4AMrqSw4XXGA22Y1BE1CzXah206jqsDqWDC4P+XWFYqG1kmv2GUXO7Xuz2htwAelzBgAKiRYAYScIDNRDqTqNsNbZRuohFAMH1clcBAZSCw+AB3ACyUeFAFEXTrzLtqFV1gZGnwEBhYHxthPhBhfv9AXcetQKW5u33B9HR9rzJHo7HHG5uCBSMlRkjyExhUg+TgJFIQHQGKIMDxSIoIB+CobCiBIyriEAA)

We can "pipe" our predicates like so :

```js

let pipefilter = (...predicates) => xs => {
  return predicates.reduce((acc, predicate) => {
    return filter(predicate, acc)
  }, xs)
}

```

Here is an application :

```js


const users = [
  {
    nom : "paul" ,
    age: 24,
    city: "Paris"
  },
    {
    nom : "henri" ,
    age: 16,
    city: "Paris"
  },
  {
    nom : "paul" ,
    age: 23,
    city: "Sens"
  }    
]

let pipefilter = (...predicates) => xs => {
  return predicates.reduce((acc, predicate) => {
    return filter(predicate, acc)
  }, xs)
}

let f = pipefilter (
  user => user.age < 18, 
  user => user.city == "Paris"
)

console.log(f(users).toArray()) // [ { nom: 'henri', age: 16, city: 'Paris' } ]

```

[Demo](https://flems.io/#0=N4IgZglgNgpgziAXAbVAOwIYFsZJAOgAsAXLKEAGhAGMB7NYmBvEAXwvW10RCggCN8AKwRU6DJsRbtOOPMNE16jZjzABXNNWIR6AKgAEkKIwBOACgAOFAwA84ASgPAAOmgNHapg+fFxidga0YHaOBhAhVua2Dk4AnhAwUAAmdgDcbqxubhpaOvoGWBiW5mDuFPZOru4eYF4+fgG2QSGVBglJqWXRDpnZaADy-EIw2vjJMJBoMAAKprSWMKbEceZuBkMjYwDmMMRztMSHcYsDYKWa2rpohuZVrA74lvNHK4sU6y4gRwCCpqYYOJfD7uaoeAwANwwUHUMEQRku+Xcd2cBlMe3UpncfwBcXwYHmWHMxEIEDCWXcFIcGTQbkaBnUcCWcAMAF4DMh1s4uR40LQsAZ4V9LBh1FAvgYQeCDBhdvCAEwAFil4OoEBWQpAMwwpjJXy57B53JqvP5goMX0ITF1EpVHllcIMAEYAGx2gxqjUWrU6vUgA0qsHgvkCzUisW2o0OhUAZndnrimoAykw4PqaqxpW4ALr9WABSwQRbGMxsnz4CvPGDJCDUDCMMKsgB8oTZLaD6OImPcVZrdYb+HRyXU1Bg5nMGGo1Bsvdr9ZgTmbxulne7RmgZisQ7njBsk+ovQzNkqfVpaHzRjLheLG6WPi5jLvS8fpnwDoMAB5nQAOGwPpneM+AH4AmbLsl82q6mm-poIedL0HAtCwPgUC0NspTmC+jj4L8-yAnccFnv0xFEWelAgEysBXAheCKgA7IgAAMbAcCAmByDwIFwIo4gqFIPBsNmVDsdw4C3qYuxoGwQA)



Generators allow to anticipate any transformations with your data, without wasting cpu cycles, and preserving memory.

And example of preserving memory is when you have to read gigabytes files size.
In order to avoid to put all the file in memory, you can read one line at a time using generators.


And they are capable of much more :-)

Beware, for very large arrays and complex transformations better use **transducers**, but that is another beast :-)