Generate sequences that have their elements computed as you go seems challenging, but fear not, we can tackle it!

![“Oh… May I help?”*](/media/01M43VX934RB46EEDRK906YYX1/going-lazy-with-racket-1.jpg "“Oh… May I help?”*")

*“Oh… May I help?”\**

So, I stumble upon this when I was trying to solve day 10 of [Advent of Code 2020](https://adventofcode.com/2020) (my code is [here](https://github.com/ruliana/aoc-2020), but I’m laaaaate!). I’d like to get sequences of consecutive elements that meet some criteria. For example, getting all consecutive odd numbers in the list `'(1 3 5 6 7 8)` will return `'((1 3 5) (7))`.

I was pretty sure that exists, but I couldn’t find it. So I build it myself.

First, I’m using the excellent [collections-lib](https://docs.racket-lang.org/collections/index.html) from Alexis King. It provides a nice unified interface to all collections in Racket. It’s essentially lazy, so it avoids running through elements until they are needed. My version needs to be compatible.

> The strategy is to build a recursive code using plain lists first, then replace "`cons”` and "`empty”` for "`stream-cons”` and "`empty-stream”`.

First, I’ve built the code to group consecutive elements on a plain list with good old recursion. My first reflex was using an accumulator to make use of [tail-call optimization](https://docs.racket-lang.org/guide/Lists__Iteration__and_Recursion.html#%28part._tail-recursion%29) but that just made the transformation more difficult. Then I’ve reverted back to non-tail-call recursion so changing the code was straightforward.

Here the version using a simple list:

<https://gist.github.com/ruliana/87e4c9d25adb2e0526bff5bb2e37cd48>

Using it like `(in-groups odd? '(1 3 5 6 7 8))` returns `'((1 3 5) (7))`.

Then, I’ve replaced all `cons` and `empty` for `stream-cons` and `empty-stream` and *voilà*! It’s done! Now I can freely use all the benefits of collections-lib and lazy collections.

Here is the final version:

<https://gist.github.com/ruliana/361a50f1fbcdda248577a6ba3cf2a880>

Using it like `(in-groups odd? '(1 3 5 6 7 8))` returns `#<stream>`, so we have to use `sequence->list`, like this `(sequence->list (in-groups odd? '(1 3 5 6 7 8)))` to get the same answer as before.

> Lazy senquences are not tail-recursive, but they don’t keep piling up on your stack.

The only changes were on lines 7 and 14, where I replaced `cons` and `empty` by `stream-cons` and `empty-stream`.

Note that `group` is a plain list on both versions. I haven’t tried a double lazy version, but it might be not that difficult to do it.

---

I hope that helps you to get a little more comfortable with lazy sequences in Racket.

Lazy sequences built with `stream-cons` also have a **very** interesting effect. They are not tail-recursive, but they don’t keep piling up on your stack. So that might be useful on some tree walking algorithms.

---

\*Three-toed sloth image by [Sergio Delgado](https://twitter.com/sdelgado) licensed under [Creative Commons](https://creativecommons.org/licenses/by-sa/3.0/deed.en).
