Hi all,
I wrote this litle snippet:
@spec map_tuples_and_stop_on_error(list, {:error | :ok, list}, fun) :: {:error | :ok, list}
def map_tuples_and_stop_on_error([], {result, elements}, fun)
when result in [:error, :ok] and is_list(elements) and is_function(fun),
do: {result, Enum.reverse(elements)}
def map_tuples_and_stop_on_error([first | rest], {result, elements}, fun)
when result in [:error, :ok] and is_list(elements) and is_function(fun) do
case fun.(first) do
{:error, _} = result -> result
{:ok, add_this} -> map_tuples_and_stop_on_error(rest, {:ok, [add_this | elements]}, fun)
end
end
test "map_tuples_and_stop_on_error" do
fun = &if &1 >= 100, do: {:error, :too_much}, else: {:ok, &1 + 1}
assert MyModule.map_tuples_and_stop_on_error([1, 2, 3, 4, 5], {:ok, []}, fun) == {:ok, [2, 3, 4, 5, 6]}
assert MyModule.map_tuples_and_stop_on_error([95, 96, 97, 98, 99], {:ok, []}, fun) == {:ok, [96, 97, 98, 99, 100]}
assert MyModule.map_tuples_and_stop_on_error([97, 98, 99, 100, 101], {:ok, []}, fun) == {:error, :too_much}
assert MyModule.map_tuples_and_stop_on_error([99, 100, 101, 102, 103], {:ok, []}, fun) == {:error, :too_much}
end
It’s like a map
but it works only with functions that return {:error | :ok, any}
and it doesn’t return error / ok tuples. Instead of returning list of {:ok, value}
it returns list with value
elements or first error tuple.
When I was writing this code I realized I can add a new element into a list using slow / improper method
elements ++ [add_this]
or just using the proper / fast method
[add_this | elements]
and at the end finish the recursion with Enum.reverse(elements)
.
Could you please tell me, would you recommend the fast method + reverse or the slow method without reverse?
Thank you.
Kind regards,
Mat