First, I am a new learner and this is my first post ! I am really happy to join the community.
I am discovering Elixir syntax and I had a quick question:
Why can’t I use this syntax ?
Enum.all?([1, 30], is_number)
If I do this I get the following error
** (CompileError) iex:9: undefined function is_number/0
(stdlib) lists.erl:1354: :lists.mapfoldl/3
(stdlib) lists.erl:1355: :lists.mapfoldl/3
I expected Elixir to find
Instead, this works:
Enum.all?([1, 30], &is_number(&1))
Enum.all?([1, "hi"], fn x -> is_number(x) end)
Functions in Elixir have both a name AND an arity (number of arguments it takes). For Elixir to find the function, it needs both. Therefore, if you use the
& capture operator, you also need to specify the function’s arity:
Enum.all?([1, 30], &is_number/1)
With your previous syntax of
Enum.all?([1, 30], is_number), Elixir doesn’t know the function’s arity. In this case, there is only one version of
is_number, but other functions with the same name can have different arities, e.g.
In Elixir, a function’s “identity” is composed of BOTH its name and arity. This is why you’ll see functions referred to as
is_number/1 and not just
The question is more about why You need to use & than function arity.
has the same result as
fn x -> is_number(x) end
and You might wonder why wrapping this inside fn -> end.
But as soon as there is more than one params… You see it starts to be clearer why the 2 forms are differents.
There is another reason, fn allows to capture the present value of variables in the scope (Closure).
iex> a = 2
iex> myfunc = fn x -> a * x end
#Function<6.127694169/1 in :erl_eval.expr/5>
iex> a = 3
iex> Enum.map([1, 2], &myfunc.(&1))
This last example is like having
fn x -> fn x -> a * x end end
It’s really fun to create functions from other functions so easily