Style: cleanest way to pipe to an Enum.map with an anonymous function

In general I’ve been sticking to this community style guide https://github.com/christopheradams/elixir_style_guide, but there’s one thing that really hurts my eyes when I see it in my code.

When I pipe a list to Enum.map or another Enum function:

[value] =
  logins
  |> Enum.filter_map(
      fn [un | _] -> un == username end,
      fn [_ | [pwd | _]] -> pwd end
    )
  |> # go on

It looks even worse if it’s a multiline function:

  "candidates"
  |> Cosmic.get_type()
  |> Enum.filter(fn
      %{"metadata" => %{"callable" => "Callable"}} -> true
      _ -> false
    end)
  |> Enum.map(fn %{"slug" => slug, "title" => name} -> %{slug: slug, name: name} end)
  |> Poison.encode()

This feels wrong! What do other people do?

1 Like

Why does it feel wrong?

I do it exactly that way, except that I lineup end) and |> in the same column:

list
|> Enum.map(fn a ->
  a
end)
|> …

But to be honest, I prefer to simply give that function a name and def(p) it:

list
|> Enum.map(&id/1)
|> …

Or using const (as an example with extra arguments:

list
|> Enum.map(&const(&1, 5))
def const(_, b), do: b
def id(a), do: a
1 Like

I find that inline anonymous function definitions are a bit of a bad habit in the JavaScript world.

Using lambda-style is fine when the function is mercilessly short. Otherwise just define a module function and use the capture syntax. And if you need to use a closure define a module function that returns an anonymous function with a closure.

defp is_user(username),
  do: fn [un | _] -> un == username end

defp extract_pwd([_ | [pwd | _]]),
  do: pwd

...

[value] =
  logins
  |> (Enum.filter_map (is_user username), &extract_pwd/1)
  |> # go on

.

defp is_callable(%{"metadata" => %{"callable" => "Callable"}}), do: true
defp is_callable(_), do: false

defp extract_slug_name(%{"slug" => slug, "title" => name}),
  do: %{slug: slug, name: name}

...

"candidates"
  |> Cosmic.get_type()
  |> Enum.filter(&is_callable/1)
  |> Enum.map(&extract_slug_name/1)
  |> Poison.encode()
4 Likes

Ah yeah, I am a recovering Node.js programmer. Then I learned Lisp and tried to program Javascript for fun for a while with only expressions, which lead to lots of immediately invoked function expressions and .filter .map chains.

I’ll define private functions. Thanks everyone!

1 Like