Erlang 生成任意元数的匿名函数?
Erlang generate anonymous function of an arbitary arity?
是否可以编写一个 returns 指定元数的匿名函数的函数?我希望能够生成一个可以作为第三个参数传递给 meck:expect/3
的函数,这样我就可以动态模拟任何数量的现有函数?
我已经做了很多搜索,看来解决这个问题的唯一方法是像这样硬编码:
gen_fun(1, Function) ->
fun(A) -> Function([A]) end;
gen_fun(2, Function) ->
fun(A, B) -> Function([A, B]) end;
...
它并不漂亮,但您可以使用与 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>
是否可以编写一个 returns 指定元数的匿名函数的函数?我希望能够生成一个可以作为第三个参数传递给 meck:expect/3
的函数,这样我就可以动态模拟任何数量的现有函数?
我已经做了很多搜索,看来解决这个问题的唯一方法是像这样硬编码:
gen_fun(1, Function) ->
fun(A) -> Function([A]) end;
gen_fun(2, Function) ->
fun(A, B) -> Function([A, B]) end;
...
它并不漂亮,但您可以使用与 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>