LazyFor → `Kernel.SpecialForms.for/1` but returning stream

The stream-based implementation of Kernel.SpecialForms.for/1. Allows the same syntax as for and acts the same way. This is an initial release. It does not yet support :into , :uniq, and :reduce options and bitstring comprehensions.

Everything else is supported.

https://hexdocs.pm/lazy_for

Examples:

iex> import LazyFor

iex> # A list generator:
iex> result = stream n <- [1, 2, 3, 4], do: n * 2
iex> Enum.to_list(result)
[2, 4, 6, 8]

iex> # A comprehension with two generators
iex> result = stream x <- [1, 2], y <- [2, 3], do: x * y
iex> Enum.to_list(result)
[2, 3, 4, 6]

iex> # A comprehension with a generator and a filter
iex> result = stream n <- [1, 2, 3, 4, 5, 6], rem(n, 2) == 0, do: n
iex> Enum.to_list(result)
[2, 4, 6]

iex> users = [user: "john", admin: "meg", guest: "barbara"]
iex> result = stream {type, name} when type != :guest <- users do
...>   String.upcase(name)
...> end
iex> Enum.to_list(result)
["JOHN", "MEG"]
4 Likes

Slightly moving forward. Simple binary comprehension and options (all but :reduce) do work.

iex|1 ▶ Enum.to_list(stream <<x <- "abcabca">>, do: x)
'abcabca'
iex|2 ▶ Enum.to_list(stream <<x <- "abcabca">>, uniq: true, do: x)
'abc'
iex|3 ▶ stream <<x <- "abcabca">>, take: 2, do: x                 
'ab'

Also :into works as a side effect (as described here)

I am not sure I am into implementing full bitstring support, but :reduce will come soon.

4 Likes

Well, the latest hot discussion about semi-mutable not actually mutable syntactic sugar reminded me of my tech debt and I implemented reduce:.

  test "binary for comprehensions with reduce, generators and filters" do
    bin = "abc"

    acc =
      stream <<x <- bin>>, Integer.is_odd(x), <<y <- "hello">>, reduce: %{} do
        inner_acc -> Map.update(inner_acc, x, [y], &[y | &1])
      end

    assert acc == %{97 => ~c"olleh", 99 => ~c"olleh"}
  end

Under the hood, the slightly modified inner clause is applied to terminate the stream. Enjoy.

2 Likes