When you define an anonymous function in elixir you get a result like this.
#Function<6.90072148/1 in :erl_eval.expr/5>
What I've noticed is that the number is based on the arity of the function. So a 1 arg function is always
#Function<6.90072148/1 in :erl_eval.expr/5>
A two arg function is always
#Function<12.90072148/2 in :erl_eval.expr/5>
A three arg function is always
#Function<18.90072148/3 in :erl_eval.expr/5>
What is the number that's being returned, and how is it being derived?
Just as the name implies, an anonymous function has no name. As we saw in the Enum lesson, these are frequently passed to other functions. To define an anonymous function in Elixir we need the fn and end keywords. Within these we can define any number of parameters and function bodies separated by -> .
__MODULE__ is a compilation environment macros which is the current module name as an atom.
An Elixir function is typically named, and is called a "named function". Functions are defined with the def keyword followed by a parameter list. A function also has a body containing the contents of the function. Like modules, the function body begins with the do keyword and ends with the end keyword.
This is the pipe operator. From the linked docs: This operator introduces the expression on the left-hand side as the first argument to the function call on the right-hand side. Examples.
The number consists of the index and a unique name of the function, which are generated by the compiler. Take a look at the implementation of the inspect protocol for functions. It contains this passage:
"#Function<#{uniq(fun_info)}/#{fun_info[:arity]} in " <>
"#{Inspect.Atom.inspect(mod)}#{extract_name(fun_info[:name])}>"
where fun_info
refers to the result of a previous call to :erlang.fun_info
. This loosely translates to the following pseudo-code, where all interpolated values refer to elements of fun_info
:
"#Function<#{new_index}.#{uniq}/#{arity} in #{module}.#{name}>"
As you have correctly observed, the part after the /
indicates the arity. module
and name
show you where the function was defined. new_index
is a pointer into the module's function table, and uniq
is a hash value of the module generated by the compiler. When you invoke :erlang.fun_info
for a function, you will be able to recognize the values from the inspect string:
iex> fun = fn x -> x end
#Function<6.90072148/1 in :erl_eval.expr/5>
iex> fun_info = :erlang.fun_info(fun)
[pid: #PID<0.58.0>,
module: :erl_eval,
new_index: 6,
new_uniq: <<171, 204, ...>>,
index: 6,
uniq: 90072148,
name: :"-expr/5-fun-4-",
arity: 1,
env: [...]]
The uniq value and the index taken together provide a way to uniquely identify an anonymous function. Be aware that inside iex
these supposedly unique values will be very similar for all functions you create, but when the code is "properly" compiled, they will be unique. Consider the following iex session:
iex> fn -> end
#Function<20.90072148/0 in :erl_eval.expr/5>
iex> fn -> end
#Function<20.90072148/0 in :erl_eval.expr/5>
iex> fn -> end
#Function<20.90072148/0 in :erl_eval.expr/5>
Now compare that to running the following file with elixir fun.exs
:
IO.inspect fn -> end
IO.inspect fn -> end
IO.inspect fn -> end
# this prints
#Function<0.120576197 in file:fun.exs>
#Function<1.120576197 in file:fun.exs>
#Function<2.120576197 in file:fun.exs>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With