Strange behavior in Elixir when updating a map inside a for loop

    list1 = [2,3,4]
    map22 = MapSet.new()
    map22 = MapSet.put(map22,25)
    for i <- list1 do
         map22 = MapSet.put(map22,i)
     end
     IO.puts("The updated map is #{inspect(map22)}")

When i run the above program i see that the updates within the for loop doesn’t work at all. Why is this so?

Sincerely,
Arvind

You can’t rebind variables from an outer scope

Each block, like for, if, case, cond, with, fn define a new scope. You can read values from outer scopes, but you can’t rebind them, as inner scopes have no influence over outer scopes.

An alternative way of writing your code would be

list1 = [2,3,4]
map22 = MapSet.new()
map22 = MapSet.put(map22,25)
map22 =
  for i <- list1, reduce: map22 do
    map22 -> MapSet.put(map22,i)
  end
IO.puts("The updated map is #{inspect(map22)}")

or using Enum.reduce:

list1 = [2,3,4]
map22 = MapSet.new()
map22 = MapSet.put(map22,25)
map22 = Enum.reduce(list1, map22, fn i, map22 -> MapSet.put(map22, i) end)
# or with capture syntax
# map22 = Enum.reduce(list1, map22, &MapSet.put(&2, &1))
IO.puts("The updated map is #{inspect(map22)}")

(untested but I just want to illustrate the idea)

You can look at Enum.reduce/2 — Elixir v1.13.2 (hexdocs.pm) for an explanation of what reducing means

5 Likes

Awesome. Thanks a lot.

Welcome to FP

4 Likes

Yeah, several times my expectations from other languages have bitten me on that! So, to give a simpler example, I’ve had to rewrite something like:

if y == z do
  x = base_value + z_increment
else
  x = base_value + general_increment
end

to something like

increment = if y == z, do: z_increment, else: general_increment
x = base_value + increment
1 Like