Shortcut for anonymous filter function that always returns true

Hi all,

for the identity function we have &(&1) as a shortcut, but &(true) does cause a compiler error. Understandably, since there is no way for the compiler to understand the arity of the function. So I was wondering, is there a shortcut for the “filter” function that that always returns true, ie., for

fn _ -> true end

Cheers
Arno

What would be a use case for a filter that doesn’t filter anything out? Can you just not apply the filter?

iex(3)> [1, 2, 3, false, nil, true] |> Enum.filter(&(!!&1 || true))
[1, 2, 3, false, nil, true]

iex(4)> [1, 2, 3, false, nil, true] |> Enum.filter(&match?(_, &1))
[1, 2, 3, false, nil, true]

I think this is a case in which Elixir prefers the explicitness of fn _ -> true end over another form, because when writing it like this it is a lot more clear that you do nothing with the argument. (Which is exactly the error you get when typing &(true).

So I don’t think there is a shorter way, unless you define it as a named function with a short way somewhere.

1 Like
def always(_), do: true

Enum.filter(enum, always/1)

Perhaps a more useful general tool would be a const function that itself produces a function that always returns a given value: const(true) = fun _ -> true, etc.

2 Likes

Something like this?

defmodule Fn do
  def const(v), do: fn _ -> v end
end

Or more like this?

defmodule Fn do
  def const(v, _), do: v
end

Usage were:

Enum.filter(list, Fn.const(true))
# vs
Enum.filter(list, &Fn.const(v, &1))
1 Like

Yes, exactly. That way you can use this in more scenarios. For example, when you want to support higher order functions for calculating something in a function, let’s say a width for something, you can simply provide a const value function for the things where you would’ve ordinarily just pass a value.

Wow … thanks for the quick responses :D.

The use case is for optional parameters where I want to allow filtering functionality. If no filter is set I am setting a default which is to bypass everything. Of course, there might be room for optimization as

Enum.filter(list, fn _ -> true end)

is just a waste of resources, but it makes for a better readibility to write

Enum.filter(list, filter_function)

and ensuring that there always is a filter function rather than distinguishing between no filter function and a provided filter function.

I very much like @gon782 and @NobbZ suggestions. Thanks a lot.

Why not just bypass the filter function itself?

collection
|> Stream.map(&do_something/1)
|> maybe_filter(should_filter?, filter_fun)
|> ...
@spec maybe_filter(Enumerable.t, boolean, ((Enum.element) -> boolean)) :: Enumerable.t
def maybe_filter(collection, false, _filter_fun), do: collection
def maybe_filter(%Stream{} = collection, true, filter_fun) do
  Stream.filter(collection, filter_fun) # lazy
end
def maybe_filter(collection, true, filter_fun) do
  Enum.filter(collection, filter_fun) # eager
end
2 Likes

Where maybe_filter/2 could be defd as:

def maybe_filter(list, fun) when is_function(fun, 1), do: Enum.filter(list, fun)
def maybe_filter(list, :no_filter), do: list
3 Likes

Nice and simple. And obvious in hindsight :smiley: