timbot

timbot

Partially applied functions and placeholder arguments

Hi there,

I am currently learning Elixir by going through the Mix and OTP guide on elixir-lang.org. I have read through the Getting Started guide already.

I am having trouble getting my head around the use of placeholder arguments when capturing and partially applying named functions. The specific examples that are confusing me are on this page here https://elixir-lang.org/getting-started/mix-otp/agent.html

def get(bucket, key) do
    Agent.get(bucket, &Map.get(&1, key))
end
def put(bucket, key, value) do
    Agent.update(bucket, &Map.put(&1, key, value))
end

If I understand correctly, the & in &Map.get and &Map.put is capturing the named functions so that they can be passed as arguments to the Agent.get and Agent.update functions. This makes sense to me. But the &1 is causing confusion.

I think the &1 is evaluating to bucket in each of these examples. I don’t see what else could be happening here. But if this is the case, then why can’t we just write bucket instead of &1? Wouldn’t that be a whole lot clearer?

I guess I could just carry on with the tutorial without properly understanding this point, but it seems like this is a crucial enough concept to ask an embarrassingly noob question on these forums.

Thanks in advance for helping me to understand this.

Marked As Solved

kokolegorille

kokolegorille

It is the state of the Agent that get passed to the anonymous function.

Also Liked

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

There is nothing magic about how &1 is working here. Rather, it’s the Agent.get function that is doing the work. &Map.get(&1, key) is just an anonymous function that takes a map and grabs a key from it. For example:

iex(1)> key = :name            
:name
iex(2)> fun = &Map.get(&1, key)
#Function<7.91303403/1 in :erl_eval.expr/5>
iex(3)> map = %{name: "Ben", country: "USA"}
%{country: "USA", name: "Ben"}
iex(4)> fun.(map) 
"Ben"

In this example, &1 becomes whatever you pass to it, in my case map

When you do:

Agent.get(bucket, &Map.get(&1, key))

This is exactly equivalent to just doing:

fun = &Map.get(&1, key)
Agent.get(bucket, fun)

where fun in that example is 100% identical to the fun in my example.

SO how does it get the process state? Well, that’s the job of Agent.get. It takes that anonymous function sends it to the process, the process calls fun with its state, and sends the result back to you.

kokolegorille

kokolegorille

Hello and welcome,

& is a shortcut for defining anonymous function, and &1, &2… are the parameters to this function.

&Map.get(&1, key)

# is equal to

fn x -> Map.get(x, key) end

You might find version with two parameters, in particular with reduce…

For example.

iex> Enum.reduce [1, 2, 3], & &1 + &2
6

# is equal to

iex> Enum.reduce [1, 2, 3], fn x, acc -> x + acc end

More on this here

kokolegorille

kokolegorille

That is the power of function as first class citizen, You can pass the implementation as an argument :slight_smile:

Where Next?

Popular in Questions Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
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
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: The documentation above suggests that while ...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
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

Other popular topics Top

marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
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
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a &gt; b) do {:ok, "a"} end if (a &lt; b) do {:ok, b} end if (a == b) do {:ok, "equa...
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
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New

Latest on Elixir Forum

We're in Beta

About us Mission Statement