function_clause 和 Erlang 中的 badarg 有什么区别?

What's the difference between function_clause and badarg in Erlang?

有时我得到的是 badarg 而不是 function_clause,但我看不到确定要显示哪一个的规则。

据我了解,当没有函数的实现与给定参数匹配时,将抛出 function_clause。关于 badarg 文档说

The argument is of wrong data type, or is otherwise badly formed.

function_clause 条件似乎涵盖了...

例如

lists:flatten(3).

抛出子句错误,而类型肯定不匹配。

函数子句是具有不同参数 patterns/guards 的定义的一部分,如

func({X, Y}) -> ...;
func(X) when X > 10 -> ...;
func(_) -> ...

function_clause 表示其中 none 个匹配。还有类似的if_clausecase_clause。对于具有单个参数的 flattenonly one clause

flatten(List) when is_list(List) ->
    do_flatten(List, []).

3 不匹配,这就是你得到 function_clause 的原因。

所以

Sometimes I get badarg instead of function_clause but I cannot see the rule that would determine which one is going to appear

这基本上是一个实现细节,您只应在调试该函数的实现时关心它。

1> F = fun({X,L}) ->  X + hd(L) end.                                                  
#Fun<erl_eval.7.91303403>
2> catch(F(5)). % 5 is not a tuple, so there is no clause in F definition which allow any evaluation 
{'EXIT',{function_clause,[{erl_eval,'-inside-an-interpreted-fun-',
                                    [5],
                                    []},
                          {erl_eval,eval_fun,6,[{file,"erl_eval.erl"},{line,829}]},
                          {erl_eval,expr,5,[{file,"erl_eval.erl"},{line,437}]},
                          {shell,exprs,7,[{file,"shell.erl"},{line,686}]},
                          {shell,eval_exprs,7,[{file,"shell.erl"},{line,642}]},
                          {shell,eval_loop,3,[{file,"shell.erl"},{line,627}]}]}}
3> catch(F({5,6})). % in the tuple, 6 is not a list, it is a bad argument for erlang:hd/1
{'EXIT',{badarg,[{erlang,hd,[6],[]},
                 {erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,684}]},
                 {erl_eval,expr,5,[{file,"erl_eval.erl"},{line,480}]},
                 {erl_eval,expr,5,[{file,"erl_eval.erl"},{line,437}]},
                 {shell,exprs,7,[{file,"shell.erl"},{line,686}]},
                 {shell,eval_exprs,7,[{file,"shell.erl"},{line,642}]},
                 {shell,eval_loop,3,[{file,"shell.erl"},{line,627}]}]}}
4> catch(F({5,[a]})). % now the error is detected in the addition you get a badarith
{'EXIT',{badarith,[{erlang,'+',[5,a],[]},
                   {erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,684}]},
                   {erl_eval,expr,5,[{file,"erl_eval.erl"},{line,437}]},
                   {shell,exprs,7,[{file,"shell.erl"},{line,686}]},
                   {shell,eval_exprs,7,[{file,"shell.erl"},{line,642}]},
                   {shell,eval_loop,3,[{file,"shell.erl"},{line,627}]}]}}
5> catch(F({5,[6]})).
11
6>

官方解释如下:

巴达格

错误的论点。参数的数据类型错误,或者格式不正确。

function_clause

计算函数调用时未找到匹配的函数子句。


有时 badarg 应该被 function_clause

覆盖

但是当做数学运算时,例如1/0会抛出badarg

在大多数情况下,当带有 guard 的函数定义将抛出 function_clause