ericky
ericky

Reputation: 1681

Pass and consume a named function in Elixir?

The following Elixir code is incorrect but conveys (I think) the desired result:

defmodule Question do
  def dbl(n), do: n * 2
  def trp(n), do: n * 3

  def consumer(xs, f) do
    Enum.filter(xs, f.(x) > 5)
  end
end

Question.consumer([1, 2, 3], dbl) # [3]
Question.consumer([1, 2, 3], trp) # [2, 3]

How should the consumer method be written to consume dbl and trp correctly? And then how would you call it?

Thank you!

EDIT:

A related question please. How would you write and call the Scala code below in Elixir:

def dbl(n: Int): Int = n * 2
def trp(n: Int): Int = n * 3

def consume(xs: List[Int], f: (Int) => Int): List[Int] =
  xs.filter(x => f(x) > 5)

consume(List(1, 2, 3), dbl) # List(3)
consume(List(1, 2, 3), trp) # List(2, 3)

(Thank you) * 2

Upvotes: 4

Views: 2408

Answers (1)

Sheharyar
Sheharyar

Reputation: 75820

The Elixir equivalent of Scala's x => f(x) > 5 is fn x -> f.(x) > 5 end. This is how you use it:

defmodule Question do
  def dbl(n), do: n * 2
  def trp(n), do: n * 3

  def consumer(list, f) do
    Enum.filter(list, fn x -> f.(x) > 5 end)
  end
end

You can then call it using:

Question.consumer([1, 2, 3], &Question.dbl/1)   # => [3]
Question.consumer([1, 2, 3], &Question.trp/1)   # => [2, 3]

Additional Notes:

  • You can also use the short-hand &(f.(&1) > 5) instead of the full function
  • Notice the & and /1 - You need to pass a complete reference to the named module methods. See the Elixir guide on the Function captures.
  • On the other hand, if you make the dbl and trp functions anonymous, you can pass them directly as arguments:

    dbl = fn n -> n * 2 end
    trp = fn n -> n * 3 end
    
    Question.consumer([1, 2, 3], dbl)   # => [3]
    Question.consumer([1, 2, 3], trp)   # => [2, 3]
    
  • For reference, read: Why are there two kinds of functions in Elixir?

Upvotes: 8

Related Questions