From the Elixir documentaion :
iex(8)> h Stream.resource
def resource(start_fun, next_fun, after_fun)
@spec resource(
(() -> acc()),
(acc() -> {[element()], acc()} | {:halt, acc()}),
(acc() -> term())
) :: Enumerable.t()
Emits a sequence of values for the given resource.
Similar to transform/3 but the initial accumulated value is computed lazily via
start_fun and executes an after_fun at the end of enumeration (both in cases of
success and failure).
Successive values are generated by calling next_fun with the previous
accumulator (the initial value being the result returned by start_fun) and it
must return a tuple containing a list of elements to be emitted and the next
accumulator. The enumeration finishes if it returns {:halt, acc}.
As the name says, this function is useful to stream values from resources.
## Examples
Stream.resource(
fn -> File.open!("sample") end,
fn file ->
case IO.read(file, :line) do
data when is_binary(data) -> {[data], file}
_ -> {:halt, file}
end
end,
fn file -> File.close(file) end
)
iex> Stream.resource(
...> fn ->
...> {:ok, pid} = StringIO.open("string")
...> pid
...> end,
...> fn pid ->
...> case IO.getn(pid, "", 1) do
...> :eof -> {:halt, pid}
...> char -> {[char], pid}
...> end
...> end,
...> fn pid -> StringIO.close(pid) end
...> ) |> Enum.to_list()
["s", "t", "r", "i", "n", "g"]
Lets try it in practice. This anonymous function creates a Stream.resource/3
which generates a stream of numbers counting down from whatever number you provide.
Function creation:
s = fn(count) -> Stream.resource(fn -> count end, fn(count) -> case count do count when count > 0 -> {[count],count - 1}; count -> {:halt,count} end end, fn _ -> :ok end) end
Function usage:
s.(15) |> Enum.each(&(IO.puts(&1)))