A little bit of context. The way I see it, there're 3 possible situations of dealing with sequence of elements in the code: 1. Sequences are considerably small (millions of elements elements): use lists 2. Neverending stream of events (e.g. queue processing): use streams 3. Something in between, i.e. sequence is finite, but might be big enough to care and avoid constructing lists in order to save memory: use streams
Now consider you'd want to do something *at the end of a sequence*, as in "*after last element was processed*" , returning the processed sequence itself. For lists it's simple: call Kernel.tap/2, ignore the argument and do your dirty side effect. For streams, not so: one obvious solution would be to wrap a stream inside a Stream.transform/4 <https://hexdocs.pm/elixir/1.14/Stream.html#transform/4>, like this: ```elixir > side_effect = fn -> IO.puts("I've processed all elements!") end > > 1..10 > |> Stream.transform(fn -> nil end, fn elem, _ -> {[elem], nil} end, fn _ -> side_effect.() end) > |> Enum.to_list() I've processed all elements! [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ``` The problem though, is that for Stream, stream exhaustion (emission of all elements in it) and stream halt is *the same thing*. So if you're to put something like Enum.take/2 at the end... ```elixir > side_effect = fn -> IO.puts("I've processed all elements!") end > > 1..10 > |> Stream.transform(fn -> nil end, fn elem, _ -> {[elem], nil} end, fn _ -> side_effect.() end) > |> Enum.take(5) I've processed all elements! [1, 2, 3, 4, 5] ``` ...it gives you not exactly what you want. The actual solution is trivial, though, and I think it's helpful enough to be considered for inclusion into the standard library. ```elixir defmodule Stream do # ... @doc """ Run a function `fun` only when the passed `enum` is completely exhausted. It's different from Stream.transform with `fun` evaluation on :halt, because in this case it would run on stopped usage of passed enum, not when enum is completely exhausted. I.e. it would run `fun` in `1..10 |> Stream.transform_on_exhaust(...) |> Enum.take(5)`, even though we haven't exhausted the stream (taking only 5 out of 10 items) """ def on_exhaust(enum, fun) when is_function(fun, 0) do Stream.concat( enum, Stream.unfold(nil, fn _ -> fun.() nil end) ) end # ... end ``` (The naming part is up for discussion, though). -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/8ffbf4a1-c63c-4201-aae8-ae2933fc06c0n%40googlegroups.com.