Search code examples
pipeelixirelixir-iex

Using pipe on next line in iex (syntax error before: '|>')


In chains of pipes in Elixir, it's standard to place the pipe at the beginning on the line:

1
|> IO.inspect(label: "initial value")
|> Kernel.+(1)
|> IO.inspect(label: "plus one")
|> Kernel.*(2)
|> IO.inspect(label: "times two")
|> Integer.to_string(2)
|> IO.inspect(label: "in binary")

However, when I try to do this in IEx, the following happens:

iex(1)> 1
1
iex(2)> |> IO.inspect(label: "initial value")
** (SyntaxError) iex:2:1: syntax error before: '|>'

It is possible to workaround by moving the pipe operator to the end of the line:

iex(1)> 1 |>
...(1)> IO.inspect(label: "initial value") |>
...(1)> Kernel.+(1) |>
...(1)> IO.inspect(label: "plus one") |>
...(1)> Kernel.*(2) |>
...(1)> IO.inspect(label: "times two") |>
...(1)> Integer.to_string(2) |>
...(1)> IO.inspect(label: "in binary")
initial value: 1
plus one: 2
times two: 4
in binary: "100"
"100"

But that's tedious and unidiomatic. Is it possible to use pipes in IEx with the pipe on the next line, like we do in source files?


Solution

  • This is supported in recent versions:

    Interactive Elixir (1.12.0) - press Ctrl+C to exit (type h() ENTER for help)
    iex(1)> [1, [2], 3]
    [1, [2], 3]
    iex(2)> |> List.flatten()
    [1, 2, 3]
    

    Prior to Elixir 1.12, it was not possible to copy-paste multi-line pipes like your example verbatim into IEx. This was a symptom of the fact that code in IEx is evaluated line-by-line.

    The simplest workaround is to wrap the expression in parentheses:

    iex(1)> (
    ...(1)>     1
    ...(1)>     |> IO.inspect(label: "initial value")
    ...(1)>     |> Kernel.+(1)
    ...(1)>     |> IO.inspect(label: "plus one")
    ...(1)>     |> Kernel.*(2)
    ...(1)>     |> IO.inspect(label: "times two")
    ...(1)>     |> Integer.to_string(2)
    ...(1)>     |> IO.inspect(label: "in binary")
    ...(1)> )
    initial value: 1
    plus one: 2
    times two: 4
    in binary: "100"
    "100"
    

    You can also escape the newlines:

    iex(1)> 1 \
    ...(1)> |> IO.inspect(label: "initial value") \
    ...(1)> |> Kernel.+(1) \
    ...(1)> |> IO.inspect(label: "plus one") \
    ...(1)> |> Kernel.*(2) \
    ...(1)> |> IO.inspect(label: "times two") \
    ...(1)> |> Integer.to_string(2) \
    ...(1)> |> IO.inspect(label: "in binary") \
    ...(1)>
    initial value: 1
    plus one: 2
    times two: 4
    in binary: "100"
    "100"