Erlang生成任意数量的匿名函数?
Posted
技术标签:
【中文标题】Erlang生成任意数量的匿名函数?【英文标题】:Erlang generate anonymous function of an arbitary arity? 【发布时间】:2021-11-13 14:15:59 【问题描述】:是否可以编写一个返回指定数量的匿名函数的函数?我希望能够生成一个可以作为第三个参数传递给meck:expect/3
的函数,这样我就可以动态模拟任何数量的现有函数?
我已经做了很多搜索,似乎解决这个问题的唯一方法是通过硬编码这样的事情:
gen_fun(1, Function) ->
fun(A) -> Function([A]) end;
gen_fun(2, Function) ->
fun(A, B) -> Function([A, B]) end;
...
【问题讨论】:
【参考方案1】:它并不漂亮,但您可以使用与 shell 相同的技巧并构建您的函数从头开始:
-module(funny).
-export([gen_fun/1, gen_fun/2]).
-spec gen_fun(function()) -> function().
gen_fun(Function) ->
arity, Arity = erlang:fun_info(Function, arity),
gen_fun(Arity, Function).
-spec gen_fun(non_neg_integer(), function()) -> function().
gen_fun(Arity, Function) ->
Params = [var, 1, list_to_atom([$X| integer_to_list(I)]) || I <- lists:seq(1, Arity)],
Anno = erl_anno:new(1),
Expr =
'fun',
Anno,
clauses, [clause, Anno, Params, [], [call, Anno, var, Anno, 'Function', Params]],
value, Fun, _Vars = erl_eval:expr(Expr, ['Function', Function]),
Fun.
然后,在 shell 中……
1> F = funny:gen_fun(fun io:format/2).
#Fun<erl_eval.43.40011524>
2> F("~ts~n", ["?"]).
?
ok
3> F1 = funny:gen_fun(fun io:format/1).
#Fun<erl_eval.44.40011524>
4> F1("?~n").
?
ok
5>
【讨论】:
感谢您的回答@BrujoBenavides!该解决方案比我的解决方案更漂亮。我在使用此解决方案时遇到的一件事是我很难理解的透析器错误:src/funny.erl Line 6: Function gen_fun/1 has no local return Line 11: Function gen_fun/2 has no local return Line 17: The call erl_eval:expr(Expr::'fun',1,'clauses',['clause',1,['var',1,atom()],[],['call',1,'var',1,'Function',[],...],...], ['Function',_,...]) does not have a term of type 'nil',erl_anno:anno() | atom(),erl_anno:anno(),_ | 'bc' | 'call' | 'case' | 'cons' | 'lc' ...
知道这可能是什么原因吗? Erlang 文档似乎并没有真正定义第一个参数的类型应该是什么 - erlang.org/doc/man/erl_parse.html#type-abstract_expr。
看起来我们正在构建的东西(即Expr
)没有合适的格式来成为erl_eval:expression()
,而erl_parse:abstract_expr()
又只是一个erl_parse:abstract_expr()
。
我使用erl_anno:new/1
修复了它的行号。
解决了,谢谢!以上是关于Erlang生成任意数量的匿名函数?的主要内容,如果未能解决你的问题,请参考以下文章