IO.inspect(Enum.sum(Enum.map(String.split("1 2 3"), &String.to_integer/1)))
6
The pipe operator |> takes the value on its left
and passes it as the first argument of the call on
its right. Nested calls read inside-out:
IO.inspect(Enum.sum(Enum.map(String.split("1 2 3"), &String.to_integer/1)))
6
The same thing, piped, reads top to bottom in the order things happen.
"1 2 3"
|> String.split()
|> Enum.map(&String.to_integer/1)
|> Enum.sum()
|> IO.inspect()
6
This works because the standard library puts the "subject" (the string, the list, the map) first. Follow the same rule in your own functions.
defmodule Text do
def shout(text, suffix \\ "!"), do: String.upcase(text) <> suffix
end
"hello" |> Text.shout() |> IO.puts()
"hello" |> Text.shout("?!") |> IO.puts()
HELLO!
HELLO?!
then/2 pipes into a position other than the first,
and tap/2 runs a side effect and passes the value
through unchanged.
5
|> then(&Integer.pow(2, &1))
|> tap(&IO.puts("2^5 is #{&1}"))
|> Kernel.*(10)
|> IO.inspect(label: "times ten")
2^5 is 32
times ten: 320
IO.inspect/2 returns its argument, so you can
sprinkle it into a pipeline to see each step.
[3, 1, 2]
|> IO.inspect(label: "input")
|> Enum.sort()
|> IO.inspect(label: "sorted")
|> Enum.reverse()
|> IO.inspect(label: "reversed")
input: [3, 1, 2]
sorted: [1, 2, 3]
reversed: [3, 2, 1]
Pitfall:
|>binds looser than arithmetic and concatenation.1 + 2 |> f()really isf(3), but"total: " <> amount |> to_string()is("total: " <> amount) |> to_string(), which crashes whenamountis an integer. Many guides (and agents) get this backwards.
amount = Enum.random([42])
try do
("total: " <> amount) |> Integer.to_string() |> IO.puts()
rescue
e in ArgumentError -> IO.puts("ArgumentError: " <> Exception.message(e))
end
ArgumentError: construction of binary failed: segment 2 of type 'binary': expected a binary but got: 42
Parenthesize what you mean, or move the pipe so the conversion happens first.
IO.puts("total: " <> (amount |> Integer.to_string()))
total: 42
Pitfall: piping into an anonymous function needs the dot,
|> f.(). And a single-step pipe (foo |> bar()) is usually clearer asbar(foo); Credo flags it for that reason.