Function Parameter Pattern Matching on multiple candidates?

Is it possible to match multiple parameters to a single function body? So for:

def foo("a" = word) do
  word
end
def foo("b" = word) do
  word
end
def foo("c" = word) do
  "not a or b!"
end

have a single definition for the first two, so something like:

def foo("a" = word) 
    foo("b" = word) do
  word
end
def foo("c" = word) do
  "not a or b!"
end

You can use a guard for that

def foo(word) when word in [“a”, “b”] do
end
6 Likes

What about in the more general pattern matching case? Ie if the pattern is not regular amongst the choices?

def foo(["a", _] = list) 
    foo([_,"b"] = list) do
  list
end
def foo(list) do
  "doesn't start with a or end with b!"
end

Is another helper function with multiple defns the way?

For a list starting with something, it’s trivial:

def foo([first | _rest]) when first in ["a", "b"] do
end

For a list ending with something, it’s more involved as the Erlang lists are single-linked lists (in the C lingo) and you have to traverse the entire list to find the ending:

def foo(list) when is_list(list) do
  if List.last(list) in ["a", "b"] do
    # all good, proceed
  else
    # report an error
  end
end

For this usually people make a public function that does these validations and handles returning errors and then define something like defp do_foo to handle the happy path only.

3 Likes

You are right but I want to add that if one has to check the last element more than once in a blue moon , maybe a list is not the correct data structure.

1 Like

Thank you all for the insight but the intent of my post wasn’t about the patterns themselves (they were just arbitrary examples) but how to write a function headers with arbitrary patterns for a single body. Given the responses, I’m assuming it’s not possible. Therefore I guess an answer is:

def foo("a" = word) do: bar(word)
def foo("b" = word) do: bar(word)
defp bar(word) do
   word
end
def foo("c" = word) do
  "not a or b!"
end

Keep in mind bar cannot be between the clauses of another function. It needs to be before or after.

1 Like

FWIW, the common convention name for bar should be do_foo as well.

To sum it all up:

def foo("a") do: do_foo("a")
def foo("b") do: do_foo("b")
def foo(word) do
  "not a or b!"
end

defp do_foo(word) do
  word
end
2 Likes

Perfect, thank you!