Anonymous functions, usually called lambdas, are created with the fn keyword, as we can see in the following example:
iex> plus_one = fn (x) -> x + 1 end #Function<6.99386804/1 in :erl_eval.expr/5> iex> plus_one.(10) 11
Here, we are defining a function that takes one argument, which we've named x, and simply adds one to the provided argument. We then bind this anonymous function to a variable named plus_one, and execute it with 10 as the argument, using the syntax we can see in the preceding snippet. As expected, we get 11 back.
There is no return keyword in Elixir –the return value of a function is the value returned by its last expression.
An anonymous function can also have multiple implementations, depending on the value and/or type of the arguments provided. Let's see this in action with an example:
Imagine that we want a special division function, that, instead of raising ArithmeticError when dividing by 0, would just return the :infinity atom. This is what the anonymous function we see here achieves. Using pattern matching, we say that when the second argument (the divisor) is 0, we simply return :infinity. Otherwise, we just use the /arithmetic operatorto perform a normal division.
Aside from the lambda with multiple bodies, notice that we prefix the unused variable with an underscore (_), as in _dividend. Besides increasing the readability of your code, following this practice will make the Elixir compiler warn you when you use a supposedly unused variable. Conversely, if you don't use a certain variable but don't prefix it with an underscore, the compiler will also warn you.
Parentheses around arguments of an anonymous function are optional. You could write the plus_one function we introduced earlier as fn x -> x + 1 end.
Beyond accepting arguments, anonymous functions can also access variables from the outer scope:
iex> x = 3 3 iex> some_fun = fn -> "variable x is #{x}" end #Function<20.99386804/0 in :erl_eval.expr/5> iex> some_fun.() "variable x is 3" iex> x = 5 5 iex> some_fun.() "variable x is 3"
As you can see, our anonymous function can access variables from the outer scope. Furthermore, the variable can be bound to another value, and our function will still hold a reference to the value that the variable had when the anonymous function was defined. This is usually called a closure: the function captures the memory locations of all variables used within it. Since every type in Elixir is immutable, that value residing on each memory reference will not change. However, this also means that these memory locations can't be immediately garbage-collected, as the lambda is still holding references to them.
We'll end this section on anonymous functions by introducing a new operator–the capture operator (represented by &).
This operator allows you to define lambdas in a more compact way:
This syntax is equivalent to the one presented before for the plus_one function. &1 represents the first argument of this lambda function—and, more generally, &n will represent the nth argument of the function. Similar to what happens in the fn notation, the parentheses are optional. However, it's better to use them, as in a real-world application, these lambda functions become hard to read without them.
Besides providing a shorter way to define lambda functions, the capture operator can also be used with named functions. We'll explore this further in the next section.