Most

Most

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))

Showing Posts 1 to 5

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

FWIW, I would cautious about using this construct, there are a couple of weird edge cases in which Kernel.+ works because it has both and unary and binary version and the parser special cases some code in that case.

This generally comes up when you find some trick that works with + but does not with *.
The underlying reason is that * does not have a unary version.

Most

Most OP

I hadn’t considered that +/2 was referencing a function form the kernel module but it makes sense now why both the capture syntaxes I cited get the same result.

Is there a special name or property that references the fact that I can’t call iex> +(1, 2) but I can call iex> 1 + 2
And that I can call iex> Kernel.+(1, 2) but not iex> 1 Kernel.+ 2

Put more generally, why does &Kernel.+/2 seem to behave differently than &+/2?

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.

Most

Most OP

Thanks for the elaborate response. This has made things much clear for me :relaxed:

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews