Reputation: 14539
Given that my function does pattern matching directly in the head, is there a way for me to check if a function has a matching pattern for a given input without calling it? Kinda like match?
but for functions. I don't care about when
and I'm only matching against atoms or atoms inside tuples.
e.g.
def init(:ok) do
...
end
and
check(&init/1, :ok) # return true
check(&init/1, :other) # return false
I'm modifying state in a GenServer, using a list of functions that handle some of the input, and ignore others. Each function takes a tuple, some state and either returns a modified state if the function head matches, or returns the state if it doesn't. I have a try/rescue wrapper function for this right now, which isn't that pretty. The inputs are variable length tuples, with the first element being an atom identifier.
Upvotes: 3
Views: 892
Reputation: 121010
Strictly speaking, it is impossible. Elixir.FunctionClauseError
is simply a wrapper for underlying erlang function_clause
runtime error.
The check is done on the fly, one might check for any particular clause, but there is no list of clauses prepared to check against. The good example would be a greedy cat, sitting in front of you; you might try to feed her with an apple, a carrot or even with a paperclip, but unless you have tried, one can’t say whether she will eat it or not.
On the other hand, one always has an option to query about Module.__info__ :functions
. It responds with an arity, so one might detect and reject all Elixir.UndefinedFunctionError
s.
But clause match is done in runtime, hence there is no way to receive a list of permitted clauses. Consider that clauses could be a cumbersome tangle of guards (when
,) explicit params (:ok
) and they even might overlap.
The question, as it stated:
check(&init/1, :ok) # return true
check(&init/1, :other) # return false
has a bruteforce solution, though. I wouldn’t recommend it, but it’s still available: implement check
as call the function and rescue from Elixir.FunctionClauseError
.
Please, also, don’t share I was the guy who had this suggested.
Upvotes: 1