'How to pass an anonymous function to the pipe in Elixir

I'd like to write the code like this:

def boundary do
  :crypto.rand_bytes(8)
  |> Base.encode16
  |> &("--------FormDataBoundary" <> &1)
end

But it doesn't work.



Solution 1:[1]

Related: if the "anonymous" function has been assigned to a variable, you can pipe to it like this:

def boundary do
  add_marker = fn (s) ->
    "--------FormDataBoundary" <> s
  end

  :crypto.rand_bytes(8)
  |> Base.encode16
  |> add_marker.()
end

Solution 2:[2]

The accepted answer works, but you can do this a bit more elegantly by using

(&"--------FormDataBoundary#{&1}").()

instead of

(&("--------FormDataBoundary" <> &1)).()

Here is the full function:

def boundary do
  :crypto.strong_rand_bytes(8)
  |> Base.encode16()
  |> (&"--------FormDataBoundary#{&1}").()
end

Bonus: I've also replaced :crypto.rand_bytes/1 (which doesn't exist in elixir 1.6+) with :crypto.strong_rand_bytes/1.

Solution 3:[3]

You can also use something like this:

def boundary do
  :crypto.rand_bytes(8)
  |> Base.encode16
  |> (fn chars -> "--------FormDataBoundary" <> chars end).()
end

One advantage of this form over others is that you can easily write simple 'case' statements:

def do_some_stuff do
  something
  |> a_named_function()
  |> (
    fn
      {:ok, something} -> something
      {:error, something_else} ->
        Logger.error "Error"
        # ...
    end
  ).()
end

From:


Using fn as above is a tiny bit clearer than couchemar's answer:

def boundary do
  :crypto.rand_bytes(8)
  |> Base.encode16
  |> (&("--------FormDataBoundary" <> &1)).()
end

... but, for your particular example, the above form using & is probably best. If the pipeline expression was more complicated, naming the anonymous function parameters might be more useful.

My answer is also a little more concise than Nathan Long's answer:

def boundary do
  add_marker = fn (s) ->
    "--------FormDataBoundary" <> s
  end

  :crypto.rand_bytes(8)
  |> Base.encode16
  |> add_marker.()
end

... tho his answer would be nicer if, for some reason, you needed to call that function more than once in the pipeline.

Solution 4:[4]

can't you literally just go?

thing
|> func_one()
|> fn input -> do_stuff_here() end)

You can do stuff like piping things directly into case like

thing
|> func_one()
|> case do

so, I would think you can just pipe into an anonymous function.

Solution 5:[5]

Elixir 1.12 introduced macro then(value, fun). Citing the docs:

then(value, fun)

Pipes value into the given fun.

In other words, it invokes fun with value as argument. This is most commonly used in pipelines, allowing you to pipe a value to a function outside of its first argument.

Your code becomes:

:crypto.strong_rand_bytes(8)
|> Base.encode16
|> then(&("--------FormDataBoundary" <> &1))

I'm using :crypto.strong_rand_bytes/1 above because :crypto.rand_bytes/1 was deprecated in Erlang/OTP 18.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nathan Long
Solution 2 Harlan T Wood
Solution 3 Kenny Evitt
Solution 4 Ian
Solution 5 Andrei Duma