有没有一种方法可以在不在Erlang中调用的情况下判断函数是否有匹配子句?

有没有一种方法可以在不在Erlang中调用的情况下判断函数是否有匹配子句?,erlang,Erlang,例如,假设我有一个名为caller的模块,其中定义的一个函数包含以下表达式: Callee:some_function(foo, Bar) 调用者可以尝试捕获函数\子句,但调用者如何知道它直接来自被调用者:某个\函数而不是其他函数调用(例如被调用者:某个\函数本身进行的调用)?您可以使用catch(被调用者:某个\函数(foo,Bar))并分析错误消息(如果有): 1> catch (lists:filter(5,[1,2,3])). {'EXIT',{function_clause,[

例如,假设我有一个名为caller的模块,其中定义的一个函数包含以下表达式:

Callee:some_function(foo, Bar)
调用者可以尝试捕获函数\子句,但调用者如何知道它直接来自被调用者:某个\函数而不是其他函数调用(例如被调用者:某个\函数本身进行的调用)?

您可以使用catch
(被调用者:某个\函数(foo,Bar))
并分析错误消息(如果有):

1> catch (lists:filter(5,[1,2,3])).
{'EXIT',{function_clause,[{lists,filter,
                                 [5,[1,2,3]],
                                 [{file,"lists.erl"},{line,1283}]},
                          {erl_eval,do_apply,6,
                                    [{file,"erl_eval.erl"},{line,661}]},
                          {erl_eval,expr,5,[{file,"erl_eval.erl"},{line,434}]},
                          {shell,exprs,7,[{file,"shell.erl"},{line,684}]},
                          {shell,eval_exprs,7,[{file,"shell.erl"},{line,639}]},
                          {shell,eval_loop,3,
                                 [{file,"shell.erl"},{line,624}]}]}}
2> catch(lists:map(fun ({X,Y}) -> X + Y end, [{1,2},{3,4}])).
[3,7]
3> catch(lists:map(fun ({X,Y}) -> X + Y end, [{1,2},{3,4,5}])).
{'EXIT',{function_clause,[{erl_eval,'-inside-an-interpreted-fun-',
                                    [{3,4,5}],
                                    []},
                          {erl_eval,expr,3,[]}]}}
4> 
4> catch(lists:map(fun ({X,Y}) -> X / Y end, [{1,2},{3,0}])).
{'EXIT',{badarith,[{erlang,'/',[3,0],[]},
                   {lists,map,2,[{file,"lists.erl"},{line,1237}]},
                   {lists,map,2,[{file,"lists.erl"},{line,1237}]},
                   {erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,661}]},
                   {erl_eval,expr,5,[{file,"erl_eval.erl"},{line,434}]},
                   {shell,exprs,7,[{file,"shell.erl"},{line,684}]},
                   {shell,eval_exprs,7,[{file,"shell.erl"},{line,639}]},
                   {shell,eval_loop,3,[{file,"shell.erl"},{line,624}]}]}}
5> 
您可以识别您正在寻找的案例,因为它具有以下形式:

{'EXIT',{function_clause,[{callee,some_function,
                                     [foo, Bar],
                                     [{file,"callee.erl"},{line,LineNumber}]}|Stack]}}
您可以使用catch
(被调用方:some_函数(foo,Bar))
并分析错误消息(如果有):

1> catch (lists:filter(5,[1,2,3])).
{'EXIT',{function_clause,[{lists,filter,
                                 [5,[1,2,3]],
                                 [{file,"lists.erl"},{line,1283}]},
                          {erl_eval,do_apply,6,
                                    [{file,"erl_eval.erl"},{line,661}]},
                          {erl_eval,expr,5,[{file,"erl_eval.erl"},{line,434}]},
                          {shell,exprs,7,[{file,"shell.erl"},{line,684}]},
                          {shell,eval_exprs,7,[{file,"shell.erl"},{line,639}]},
                          {shell,eval_loop,3,
                                 [{file,"shell.erl"},{line,624}]}]}}
2> catch(lists:map(fun ({X,Y}) -> X + Y end, [{1,2},{3,4}])).
[3,7]
3> catch(lists:map(fun ({X,Y}) -> X + Y end, [{1,2},{3,4,5}])).
{'EXIT',{function_clause,[{erl_eval,'-inside-an-interpreted-fun-',
                                    [{3,4,5}],
                                    []},
                          {erl_eval,expr,3,[]}]}}
4> 
4> catch(lists:map(fun ({X,Y}) -> X / Y end, [{1,2},{3,0}])).
{'EXIT',{badarith,[{erlang,'/',[3,0],[]},
                   {lists,map,2,[{file,"lists.erl"},{line,1237}]},
                   {lists,map,2,[{file,"lists.erl"},{line,1237}]},
                   {erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,661}]},
                   {erl_eval,expr,5,[{file,"erl_eval.erl"},{line,434}]},
                   {shell,exprs,7,[{file,"shell.erl"},{line,684}]},
                   {shell,eval_exprs,7,[{file,"shell.erl"},{line,639}]},
                   {shell,eval_loop,3,[{file,"shell.erl"},{line,624}]}]}}
5> 
您可以识别您正在寻找的案例,因为它具有以下形式:

{'EXIT',{function_clause,[{callee,some_function,
                                     [foo, Bar],
                                     [{file,"callee.erl"},{line,LineNumber}]}|Stack]}}

您可以使用try-catch捕捉
function\u子句
错误,并检查堆栈跟踪是否匹配:

-module(foo).

-compile(export_all).

maybe_apply(Mod, Fun, Args) ->
    try apply(Mod, Fun, Args)
    catch
        error:function_clause ->
            case erlang:get_stacktrace() of
                [{Mod, Fun, Args} | _] ->
                    {error, function_clause};
                [{Mod, Fun, Args, _LineNumber} | _] ->
                    {error, function_clause};
                Stacktrace ->
                    {error, other_function_clause, Stacktrace}
            end
    end.
下面是一个示例,说明如何区分
列表:过滤器
本身中的函数子句错误和
列表:过滤器
调用的函数中的函数子句:

> foo:maybe_apply(lists, filter, [x, [1,2,3]]).
{error,function_clause}
> foo:maybe_apply(lists, filter, [fun(x) -> true end, [1,2,3]]).
{error,other_function_clause,
       [{erl_eval,'-inside-an-interpreted-fun-',[1],[]},
        {erl_eval,expr,3,[]}]}

您可以使用try-catch捕捉
function\u子句
错误,并检查堆栈跟踪是否匹配:

-module(foo).

-compile(export_all).

maybe_apply(Mod, Fun, Args) ->
    try apply(Mod, Fun, Args)
    catch
        error:function_clause ->
            case erlang:get_stacktrace() of
                [{Mod, Fun, Args} | _] ->
                    {error, function_clause};
                [{Mod, Fun, Args, _LineNumber} | _] ->
                    {error, function_clause};
                Stacktrace ->
                    {error, other_function_clause, Stacktrace}
            end
    end.
下面是一个示例,说明如何区分
列表:过滤器
本身中的函数子句错误和
列表:过滤器
调用的函数中的函数子句:

> foo:maybe_apply(lists, filter, [x, [1,2,3]]).
{error,function_clause}
> foo:maybe_apply(lists, filter, [fun(x) -> true end, [1,2,3]]).
{error,other_function_clause,
       [{erl_eval,'-inside-an-interpreted-fun-',[1],[]},
        {erl_eval,expr,3,[]}]}

通过捕获
catch Callee:some_函数(…)
的值,您可以让您的生活变得更轻松。在发生运行时错误的情况下,将获得堆栈跟踪作为元组的第三个元素。看。啊,我想get_stacktrace可能是关键。出于某种原因,它没有达到我第一次尝试时的预期效果。谢谢我猜这个解决方案确实调用被调用方来探测它是否有匹配子句。不过,它确实区分了匹配失败和其他失败,在许多情况下,这同样好。通过捕获
catch Callee:some_函数(…)
的值,可以让您的生活更轻松一些。在发生运行时错误的情况下,将获得堆栈跟踪作为元组的第三个元素。看。啊,我想get_stacktrace可能是关键。出于某种原因,它没有达到我第一次尝试时的预期效果。谢谢我猜这个解决方案确实调用被调用方来探测它是否有匹配子句。尽管如此,它还是区分了匹配失败和其他失败,在许多情况下,这是一样好的。我认为您应该能够(1)找到模块源文件(2)解析文件(3)评估函数头以查看它们是否匹配。不过,这需要做很多工作。我认为您应该能够(1)找到模块源文件(2)解析文件(3)评估函数头,看看它们是否匹配。不过这需要做很多工作。妮特:被调用方可以通过返回相同形式的值来愚弄您。正如其他答案中所建议的,使用try+catch似乎更好。但还是要谢谢你!nit:被调用方可以通过返回相同形式的值来愚弄您。正如其他答案中所建议的,使用try+catch似乎更好。但还是要谢谢你!