Most

Most

Why is the capture syntax &+/2 equivalent to &(&1 + &2)

I don’t understand how the capture syntax in the following expression is aware of how to use arguments without specifying &1 and &2:
Enum.reduce([1, 2, 3], 0, &+/2)

I understand this version of an equivalent expression since it is explicit how the arguments &1 and &2 are used in the function:
Enum.reduce([1, 2, 3], 0, &(&1 + &2))

Most Liked

peerreynders

peerreynders

It simply takes advantage of the positional function parameters.

+/2 is Kernel.+/2, i.e. Kernel.+(left, right) is equivalent to left + right.

The & operator captures the function rather than evaluate it - so it’s &Kernel.+/2 or &+/2.

Now look at the spec for Enum.reduce/3

reduce(t, any, (element, any -> any)) :: any

(element, any -> any) tells us that it takes a two parameter function. The first parameter (element) comes from the enumeration, the second parameter (any) is the accumulator which is the same type as the function’s result.

So the element (first) argument goes into the left parameter and the any (second) argument goes into right parameter of Kernel.+/2 (… and the result becomes the next right and so on).

bbense

bbense

Let’s start with some iex

iex(1)> h Kernel.+/1
def +(value)
Arithmetic unary plus.
Allowed in guard tests. Inlined by the compiler.
Examples
┃ iex> +1
┃ 1
iex(2)> h Kernel.+/2
def +(left, right)
Arithmetic addition.
Allowed in guard tests. Inlined by the compiler.
Examples
┃ iex> 1 + 2
┃ 3

The important thing to remember with Elixir is that no matter what the syntax looks like, it all gets turned into function calls. Every time you use + it gets turned into one of those two functions.

iex(3)> quote do: 1 + 2
{:+, [context: Elixir, import: Kernel], [1, 2]}
iex(4)> quote do: + 1
{:+, [context: Elixir, import: Kernel], [1]}

So let’s look at what the parser sees in each case.

iex> +(1, 2)

In this case the parser looks to somehow call Kernel.+1/ but it’s given an arg list that
is two elements long. This generates an syntax error.

iex> 1 Kernel.+ 2

Here the parser sees a number so it starts looking for an infix operator it can turn into a function call. While + is defined as an infix operator, arbitrary elixir functions cannot be used
as infix operators. So again it generates a syntax error.

What is going on is that the parser is attempting to be as friendly as possible and allow you to use constructs you are familiar with like 1 + 2. However, that can only be extended so far before it starts to break the underlying model of a functional programming language. + is particularly tricky since it exists in the parser as both a prefix and infix operator.

The effects you see are the attempts of the parser to understand + as both. Once you
put Kernel.+ into the equation all the special parsing rules are turned off, and it behaves like any other Elixir function.

Where Next?

Popular in Questions Top

chokchit
** (DBConnection.ConnectionError) connection not available and request was dropped from queue after 2733ms. You can configure how long re...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
nobody
How to bind a phoenix app to a specific ip address? could not find anything about that, nowhere, unfortunately, but for me this is quite...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call t...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

Other popular topics Top

Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New

We're in Beta

About us Mission Statement