Elixir by Example

Anonymous Functions

Edit any cell and run it in your browser Download source

Anonymous functions are values. Create them with fn, call them with a dot.

add = fn a, b -> a + b end
IO.inspect(add.(1, 2))
3

The dot separates calling a variable holding a function from calling a named function.

IO.inspect(is_function(add))
IO.inspect(is_function(add, 2))
true
true

A function can have several clauses, matched like case. All clauses must take the same number of arguments.

describe = fn
  [] -> "empty"
  [_] -> "one item"
  list when is_list(list) -> "#{length(list)} items"
end

IO.inspect(describe.([]))
IO.inspect(describe.([1, 2, 3]))
"empty"
"3 items"

Functions close over the variables around them. The value is captured at creation time.

greeting = "Hello"
greet = fn name -> "#{greeting}, #{name}!" end
greeting = "Bye"
IO.inspect(greet.("Ada"))
IO.inspect(greeting)
"Hello, Ada!"
"Bye"

The capture operator & turns a named function into a value. Name it with its arity.

upcase = &String.upcase/1
IO.inspect(upcase.("elixir"))
IO.inspect(Enum.map(["a", "b"], &String.upcase/1))
"ELIXIR"
["A", "B"]

& also builds short anonymous functions, with &1, &2 as the arguments.

double = &(&1 * 2)
IO.inspect(Enum.map([1, 2, 3], double))
IO.inspect(Enum.reduce([1, 2, 3], 0, &(&1 + &2)))
[2, 4, 6]
6

Functions that return functions.

multiplier = fn factor -> fn x -> x * factor end end
triple = multiplier.(3)
IO.inspect(triple.(5))
15

Pitfall: forgetting the dot. add(1, 2) looks for a named function add/2 and fails with undefined function add/2. Variables holding functions are always called as add.(1, 2).

Pitfall: &(&1) style captures get unreadable fast. If you need &1 twice or nested captures, write fn x -> ... end. Captures can't be nested at all.