for
is an unfortunate construct in Elixir IMO. Especially for beginners who come from imperative languages. Because it’s not a for
, it’s a list comprehension
list_of_transformed_data = for x <- some_list_of_data, do
transform(x)
end
Is equivalent to:
%% erlang
list_of_transformed_data = [ transform(X) || X <- Some_list_of_data ]
# python
list_of_transformed_data = [ transform(x) for x in some_list_of_data ]
And for languages that don’t have comprehensions:
// Javascript
const list_of_transformed_data = some_list_of_data.map(x => transform(x));
And as Javascript example shows, you can view Elixir’s for
as an Enum.map
(it’ not strictly true, but it helps with the metal model):
list_of_transformed_data = for x <- some_list_of_data, do
transform(x)
end
# is functionally the same as
list_of_transformed_data = Enum.map(list_of_data, fn x -> transform(x) end)
And in Elixir you can’t really change variables. You can only assign new values to variables that are in the same scope:
# elixir
x = %{ a: "b" }
x.a = "c" # this is invalid. you can't changed x's data this way
x = [] # this is valid, you can reassign a value to a variable
x = %{ a: "c" } # this is also valid, we're assigning a new value
So, all together this becomes:
succeeded = []
failed = []
## for returns a list with transformed data
result = for bin_struct <- params do
case UserData.create_bin(bin_struct) do
{:ok, %Bin{}} ->
# here we are in the scope of `case` inside the scope of `for`
# `succeded =` introduces a new variable that shadows the global variable
succeeded = [bin_struct["id"] | succeeded]
{:error, error} ->
# here we are in the scope of `case` inside the scope of `for`
# `failed =` introduces a new variable that shadows the global variable
failed = [bin_struct["id"] | failed]
end
end
## here `result` will contain a list all the transformations that happened on the data
## and global variables `succeeded` and `failed` will remain the same