I realized that what we need for case like this is something similar to Enum.reduce_map/3, but that it will iterate not based on the number of elements in the enumerable, but based on whether the enumerable still have elements left to be processed.
Please anybody tell me if I missed this function and I have reinvented the wheel (it only works with lists though)
defmodule LittleChallenge do
@spec iterate_until_empty(list, term, (list, term -> {list, term})) :: term
def iterate_until_empty(list, acc, fun) when is_list(list) and is_function(fun, 2),
do: do_iterate_until_empty(list, acc, fun)
defp do_iterate_until_empty([], acc, _fun),
do: acc
defp do_iterate_until_empty(list, acc, fun) do
{list, acc} = fun.(list, acc)
do_iterate_until_empty(list, acc, fun)
end
end
and you will do something like this,
["x", "y", "z"]
|> LittleChallenge.iterate_until_empty([], fn
list, [] ->
{list, [list]}
list, acc ->
case :lists.droplast(list) do
[] ->
{[], acc}
term ->
{term, [term | acc]}
end
end)