Capture operator `&` ampersand for a map - how to refer to a second variable?

Given this:


m1 = %{a: 1, b: 44, c: 66}
a1 = Enum.map(m1, fn {k, v} -> v end)

How can I do the same thing with the & operator?

a1 = Enum.map(m1, &(&2)) # doesn't compile, capture &2 cannot be defined without &1

How to refer to k and v in such cases?

Enum.map is passing elements of the map as a single argument - a {key, value} tuple. The fn version pattern-matches on that to extract the second element.

To do this with &, you’ll need to use elem explicitly:

a1 = Enum.map(m1, &elem(&1,1))
2 Likes

I have a related question, I hope this is good place to ask.

I need to convert a mac address to a string, so I do this:

mac = [222, 173, 190, 175, 255, 255]                                  
mac |> Enum.map(&Integer.to_string()/1)|> Enum.join(".")              
"222.173.190.175.255.255"

How to do it if I want to convert it to a hex number, but using the capture operator instead of writing the full expression: fn x → x end

mac |> Enum.map(fn x -> Integer.to_string(x, 16) end)|> Enum.join(".")                                                                             
"DE.AD.BE.AF.FF.FF"
mac
|> Enum.map(&(Integer.to_string(&1, 16)))
|> Enum.join(".")
2 Likes

There is also Enum.map_join/3:

 Enum.map_join(mac, ".", &Integer.to_string(&1, 16))
4 Likes

I will do it like this:
a1 = Enum.map(m1,&elme(&1,1))
& in some way like Function.bind in js, but I comfused by why can not reference a named function just by it’s name, but must do like &String.length/1.

If you don’t you use the capture operator (&) the function will be evaluated in place.

The short answer is that when calling a function, parens are optional.

iex> # example 1
iex> to_string(1)
"1"
iex> to_string 1
"1"
iex> # example 2
iex> DateTime.utc_now()
~U[2022-05-09 04:05:37.257950Z]
iex> DateTime.utc_now
~U[2022-05-09 04:05:38.562910Z]

So, as you can probably see, simply “referencing” a function without parens also calls it.

To add to the short answer, and this is a thing that comes up all the time so it’s very easy to google more info about (and I sincerely don’t mean that in a RTMF way), functions are referenced by both their name and their arity.

A quick example:

defmodule Math do
  def add(a, b) do
    a + b
  end

  def add(a, b, c) do
    a + b + c
  end
end

Under the hood, add(a, b) and add(a, b, c) are compiled as completely separate and wholly unrelated functions. The /1 in your example denotes that you are calling the function named length with a single argument (that’s the /1 part) on the String module.

3 Likes

Thanks.