Using a map after do: in a list comprehension

These two work:

iex(1)> for {key, val} <- %{"a" => 1, "b" => 2}, do: {key, val * val} 
[{"a", 1}, {"b", 4}]
iex(2)> for {key, val} <- %{"a" => 1, "b" => 2}, into: %{}, do: {key, val * val} 
%{"a" => 1, "b" => 4}

But this one gives syntax error:

iex(3)> for {key, val} <- %{"a" => 1, "b" => 2}, do: %{key, val * val}            
** (SyntaxError) iex:3:62: syntax error before: '}'
    |
  3 | for {key, val} <- %{"a" => 1, "b" => 2}, do: %{key, val * val} 
    |                                                              ^

Why?
Why can’t we use map directly after the do: in list-comprehensions?

1 Like

I think you have a synthax error on the way you’re trying to define the map. It is not about the for or do.

One way you could achieve the map definition would be :

%{"#{key}": val * val}

or

%{"#{key}" => val * val}

2 Likes

Exactly, the first one works because what he is defining is a tuple, not a map.

2 Likes

Yes, it’s a tuple not a map, and not even a tuple, because tuple doesn’t have %{. :slight_smile:

I did it accidentally and it took time to catch the mistake. I wanted to see if someone else can catch the mistake, because the error message doesn’t specifically point it out.

%{"#{ isn’t even needed, using key directly works.

for {key, val} <- %{"a" => 1, "b" => 2}, do: %{key => val * val} works.

2 Likes

Your map syntax itself is invalid

iex(1)> {"a", 1} # valid tuple syntax
{"a", 1}

iex(2)> %{"a" => 1} # valid map syntax
%{"a" => 1}

iex(3)> %{"a", 1} # invalid
** (SyntaxError) iex:3:6: syntax error before: ','
    |
 30 | %{"a", 1}
    |      ^

1 Like

Ah you’re right ! ^^
No string interpolation is necessary indeed.

I tought it won’t work for map with atom keys, but it also works as well:

iex(1)> key = :a
:a
iex(2)> %{key => 1}               
%{a: 1}
iex(3)>
1 Like

It’s interesting that the first syntax error points to the end of the malformed map, but the second one to the correct place, at the comma. Perhaps a bug because of the for comprehension?

Due to the for comprehension, yes, but I would hesitate to label it a bug. for is a macro, and the code is being received as quoted expressions. I’ve written macros but my knowledge is not very deep to understand error handling and introspection. The pointer seems to be pointing more generally to the offending expression, maybe because of how these details are implemented

Maps are valid returns for for, unless into: %{} is supplied as well. So it’s tricky.