Elixir basics · Lesson 08 (open contents)
Unpack &1 and the pipe
Write a full anonymous function before reading captures, Enum, and `|>`.
Copy all of it: from the long form to the short form
All three parts give a function to another function.
# Start with the full form: number is each value received
long_double = fn number -> number * 2 end
Enum.map([1, 2, 3], long_double)
# Now the short form: &1 is still each value received
Enum.map([1, 2, 3], &(&1 * 2))
# Capture the existing String.trim/1 function
[" peach", "plum "] |> Enum.map(&String.trim/1)
|> Enum.join(", ")- The first two parts both return
[2, 4, 6]. - The last pipeline returns
"peach, plum". &1only has meaning inside a short capture expression.
Read from the first line down
Enum.map/2takes two arguments: a collection and a function. That is why its name ends in/2.&(&1 * 2)means the same asfn number -> number * 2 end. Expand it when the short form feels unclear.&String.trim/1does not calltrimyet. It gives that function toEnum.map/2.- The last line means
Enum.join(previous_result, ", "). The pipe fills only the first argument automatically.
Symbols are not secret signs
&(&1 * 2)Create an anonymous function. &1 is its first argument. The full form is fn number -> number * 2 end.
&String.trim/1Capture the existing String.trim/1 function so other code can call it later.
|>Send the result on the left into the first argument position of the function on the right.
Match each name to its meaning
capture operator
& can capture an existing function or create a short anonymous function.
Enum.map/2
Give each item in a collection to a function, then collect all the new return values.
pipe operator
|> puts the result on the left into the first argument position on the right.
Why these forms are useful
&1 is an argument placeholder, not a variable on its own. It only has meaning inside a capture expression that begins with &.
Run the full form fn number -> number * 2 end first. Then run &(&1 * 2) and compare the same result.
Functions in Enum process the items in a collection. The pipe |> places the result on its left into the first argument position of the function on its right.
Why this shape?
Why pass data through a series of small steps?
A pipeline turns nested calls into a top-to-bottom data journey. Each step should still be understandable and testable on its own.
A pipe is not a superior loop. If argument order is awkward or a step hides substantial I/O, an ordinary call can be clearer.
Coming from Java, Python, or JavaScript
Java
- Familiar starting point
- Stream chains or fluent method calls.
- What BEAM changes
- Elixir
|>inserts the left value into the next call; Erlang usually nests calls or names intermediate values. - False friend
Enumis usually eager.Streamis lazy.
Python
- Familiar starting point
- Generators, comprehensions, and named intermediate values.
- What BEAM changes
- Captures and pipes compose small functions without mutating a list.
- False friend
&String.trim/1is a function value;String.trim/1only names a function and arity.
JavaScript
- Familiar starting point
- map/filter chains, callbacks, and iterators.
- What BEAM changes
- Values are immutable by default; each step returns another result.
- False friend
- Do not read
&1as JavaScript's bitwise ampersand.
Close the answer and try
Add 1 with a full function and with &1. Then write a pipe that trims two strings with &String.trim/1 and joins them.
# First: full function, then &1
full_result = Enum.map([2, 3, 4], fn number -> ____ end)
short_result = Enum.map([2, 3, 4], &(____))
# Next: capture String.trim/1 inside a pipe
clean_text =
[" red", "blue "]
|> Enum.map(____)
|> Enum.join(____)
{full_result, short_result, clean_text}Target result: The result should be {[3, 4, 5], [3, 4, 5], "red, blue"}.
Stuck? Read one hint
Use number + 1, &1 + 1, &String.trim/1, and the separator ", ".
After you run it, see one answer
# Full function, then its &1 short form
full_result = Enum.map([2, 3, 4], fn number -> number + 1 end)
short_result = Enum.map([2, 3, 4], &(&1 + 1))
# Capture trim/1 and write the pipe
clean_text =
[" red", "blue "]
|> Enum.map(&String.trim/1)
|> Enum.join(", ")
{full_result, short_result, clean_text}Think about it: Does `&String.trim/1` immediately remove spaces from a string?
No. It only captures the function. The function runs later, when Enum.map/2 gives each string to it.
Remember these three lines
- 1
Run the full anonymous function before shortening it.
- 2
&1is the first argument placeholder inside a capture expression. - 3
&String.trim/1captures a named function;|>passes a result onward.