Reading — step 1 of 7
Learn
Elixir is a functional language — functions are values. Anonymous functions, the capture operator &, and partial application are daily-use tools.
fn — anonymous functions
add = fn a, b -> a + b end
add.(3, 4) # 7 — note the DOT
square = fn n -> n * n end
square.(5) # 25
Anonymous functions REQUIRE the dot to call: fun.(args). Named functions DON'T: Module.fun(args). Easy to forget.
Multi-clause anonymous functions
classify = fn
n when n < 0 -> :negative
0 -> :zero
n when n > 0 -> :positive
end
classify.(-5) # :negative
classify.(0) # :zero
classify.(7) # :positive
Like a case expression but as a value. Useful for callbacks with branching logic.
& — capture operator (function references)
Get a reference to a NAMED function:
upcase = &String.upcase/1 # captures String.upcase, arity 1
upcase.("hello") # "HELLO"
# Use as a value:
Enum.map(["a", "b", "c"], &String.upcase/1) # ["A", "B", "C"]
The syntax: &Module.function/arity. Arity matters because Elixir distinguishes String.split/2 (2 args) from String.split/3 (3 args).
& — shorthand for anonymous functions
The & operator also creates anonymous functions inline:
# These are equivalent:
fn x -> x * 2 end
&(&1 * 2)
# Multiple args:
fn a, b -> a + b end
&(&1 + &2)
# Used heavily in pipelines:
Enum.map(nums, &(&1 * 2))
Enum.filter(nums, &(&1 > 5))
&1, &2, ... refer to the first, second, ... argument. Concise for simple expressions; harder to read for complex ones.
Rule of thumb: & for one-line callbacks. fn ... -> ... end for anything with multiple steps.
Higher-order functions
# Pass functions as arguments:
Enum.map([1, 2, 3], fn n -> n * 2 end)
Enum.map([1, 2, 3], &(&1 * 2))
Enum.map([1, 2, 3], &double/1) # if `double` is named
# Return functions:
defmodule Multiplier do
def by(n), do: fn x -> x * n end
end
times_3 = Multiplier.by(3)
times_3.(7) # 21 — closure captured n=3
Closures capture their environment. Each call to Multiplier.by/1 creates a fresh closure.
Partial application via the capture operator
add = fn a, b -> a + b end
add_five = &add.(5, &1) # bind first arg, leave second free
add_five.(10) # 15
# More common with named functions:
increment = &Kernel.+(&1, 1)
increment.(5) # 6
Not strict partial application (you can't "curry" arbitrarily) but covers most needs.
Pipelines with capture
[1, 2, 3, 4, 5]
|> Enum.filter(&(&1 > 2))
|> Enum.map(&(&1 * &1))
|> Enum.sum()
# 50 (= 9 + 16 + 25)
Canonical Elixir style: pipeline of small & lambdas.
Common mistakes
- Forgetting the dot to call —
add(1, 2)for an anonymous function fails. Must beadd.(1, 2). - Using
&shorthand for complex bodies —&(&1 |> something |> &2)is unreadable. Usefnfor non-trivial logic. - Mistaking
&1for$1— different syntax.&1is bash;&is Elixir's positional placeholder. - Forgetting arity on captures —
&String.upcasedoesn't compile; you need&String.upcase/1. - Confusing
&capture vs&placeholder — context-dependent.&Module.fun/arityis capture;&(...)with&Ninside is placeholder syntax.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…