Created
July 13, 2016 02:07
-
-
Save lalbuquerque/2d4555561b5aa3f5d57649abf0ba01f5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@doc """ | |
Pipe operator. | |
This operator introduces the expression on the left-hand side as | |
the first argument to the function call on the right-hand side. | |
## Examples | |
iex> [1, [2], 3] |> List.flatten() | |
[1, 2, 3] | |
The example above is the same as calling `List.flatten([1, [2], 3])`. | |
The `|>` operator is mostly useful when there is a desire to execute a series | |
of operations resembling a pipeline: | |
iex> [1, [2], 3] |> List.flatten |> Enum.map(fn x -> x * 2 end) | |
[2, 4, 6] | |
In the example above, the list `[1, [2], 3]` is passed as the first argument | |
to the `List.flatten/1` function, then the flattened list is passed as the | |
first argument to the `Enum.map/2` function which doubles each element of the | |
list. | |
In other words, the expression above simply translates to: | |
Enum.map(List.flatten([1, [2], 3]), fn x -> x * 2 end) | |
## Pitfalls | |
There are two common pitfalls when using the pipe operator. | |
The first one is related to operator precedence. For example, | |
the following expression: | |
String.graphemes "Hello" |> Enum.reverse | |
Translates to: | |
String.graphemes("Hello" |> Enum.reverse) | |
which results in an error as the `Enumerable` protocol is not defined | |
for binaries. Adding explicit parentheses resolves the ambiguity: | |
String.graphemes("Hello") |> Enum.reverse | |
Or, even better: | |
"Hello" |> String.graphemes |> Enum.reverse | |
The second pitfall is that the `|>` operator works on calls. | |
For example, when you write: | |
"Hello" |> some_function() | |
Elixir sees the right-hand side is a function call and pipes | |
to it. This means that, if you want to pipe to an anonymous | |
or captured function, it must also be explicitly called. | |
Given the anonymous function: | |
fun = fn x -> IO.puts(x) end | |
fun.("Hello") | |
This won't work as it will rather try to invoke the local | |
function `fun`: | |
"Hello" |> fun() | |
This works: | |
"Hello" |> fun.() | |
As you can see, the `|>` operator retains the same semantics | |
as when the pipe is not used since both require the `fun.(...)` | |
notation. | |
""" | |
defmacro left |> right do | |
[{h, _} | t] = Macro.unpipe({:|>, [], [left, right]}) | |
:lists.foldl fn {x, pos}, acc -> | |
# TODO: raise an error in `Macro.pipe/3` by 1.5 | |
case Macro.pipe_warning(x) do | |
nil -> :ok | |
message -> | |
:elixir_errors.warn(__CALLER__.line, __CALLER__.file, message) | |
end | |
Macro.pipe(acc, x, pos) | |
end, h, t | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment