Elixir basics · Lesson 08 (open contents)
01 · Let the code speak02 · Meet six kinds of values03 · Put values together04 · Build a new list05 · Make the shapes match06 · Choose with case07 · Parse a number safely08 · Unpack &1 and the pipe09 · Put code in a project10 · Ask precise true-or-false questions11 · Read and update nested data12 · Count visible text and bytes13 · Let function clauses choose14 · Solve a list twice15 · Choose the smallest clear control form16 · Give domain data a shape17 · Put one tested module in Mix18 · Make success and failure predictable19 · Read and write one real file20 · Take only the data you need21 · Give different data one shared action22 · Write a callback contract23 · Write down the data contract24 · Test behavior and boundaries25 · Turn a project into a command26 · Write the project promise27 · Parse one real line28 · Keep the public API small29 · Make the promise executable30 · Package the edge and leave clues31 · Prove the project is done
ELIXIR · SCRATCH · LESSON 0835 minutes

Unpack &1 and the pipe

Write a full anonymous function before reading captures, Enum, and `|>`.

01 · Start with the whole example

Copy all of it: from the long form to the short form

All three parts give a function to another function.

Elixir
# 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(", ")
Check the result first
  • The first two parts both return [2, 4, 6].
  • The last pipeline returns "peach, plum".
  • &1 only has meaning inside a short capture expression.
02 · Take the code apart

Read from the first line down

  1. Enum.map/2 takes two arguments: a collection and a function. That is why its name ends in /2.
  2. &(&1 * 2) means the same as fn number -> number * 2 end. Expand it when the short form feels unclear.
  3. &String.trim/1 does not call trim yet. It gives that function to Enum.map/2.
  4. The last line means Enum.join(previous_result, ", "). The pipe fills only the first argument automatically.
03 · Meet the new symbols

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/1

Capture 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.

04 · Ideas inside the code

Match each name to its meaning

01

capture operator

& can capture an existing function or create a short anonymous function.

02

Enum.map/2

Give each item in a collection to a function, then collect all the new return values.

03

pipe operator

|> puts the result on the left into the first argument position on the right.

05 · Make the idea clear

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.

DESIGN DECISION

Why this shape?

Why pass data through a series of small steps?

Choice

A pipeline turns nested calls into a top-to-bottom data journey. Each step should still be understandable and testable on its own.

Cost and boundary

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.

A FAMILIAR POINT OF VIEW

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
Enum is usually eager. Stream is 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/1 is a function value; String.trim/1 only 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 &1 as JavaScript's bitwise ampersand.
06 · Change it yourself

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.

Practice starting point
# 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
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.

Take with you

Remember these three lines

  1. 1

    Run the full anonymous function before shortening it.

  2. 2

    &1 is the first argument placeholder inside a capture expression.

  3. 3

    &String.trim/1 captures a named function; |> passes a result onward.

Lesson completeRun the code once, then mark this lesson as done.