RosettaCodeData/Task/Currying/Erlang/currying.erl

63 lines
1.8 KiB
Erlang

-module(currying).
-compile(export_all).
% Function that curry the first or the second argument of a given function of arity 2
curry_first(F,X) ->
fun(Y) -> F(X,Y) end.
curry_second(F,Y) ->
fun(X) -> F(X,Y) end.
% Usual curry
curry(Fun,Arg) ->
case erlang:fun_info(Fun,arity) of
{arity,0} ->
erlang:error(badarg);
{arity,ArityFun} ->
create_ano_fun(ArityFun,Fun,Arg);
_ ->
erlang:error(badarg)
end.
create_ano_fun(Arity,Fun,Arg) ->
Pars =
[{var,1,list_to_atom(lists:flatten(io_lib:format("X~p", [N])))}
|| N <- lists:seq(2,Arity)],
Ano =
{'fun',1,
{clauses,[{clause,1,Pars,[],
[{call,1,{var,1,'Fun'},[{var,1,'Arg'}] ++ Pars}]}]}},
{_,Result,_} = erl_eval:expr(Ano, [{'Arg',Arg},{'Fun',Fun}]),
Result.
% Generalization of the currying
curry_gen(Fun,GivenArgs,PosGivenArgs,PosParArgs) ->
Pos = PosGivenArgs ++ PosParArgs,
case erlang:fun_info(Fun,arity) of
{arity,ArityFun} ->
case ((length(GivenArgs) + length(PosParArgs)) == ArityFun) and
(length(GivenArgs) == length(PosGivenArgs)) and
(length(Pos) == sets:size(sets:from_list(Pos))) of
true ->
fun(ParArgs) ->
case length(ParArgs) == length(PosParArgs) of
true ->
Given = lists:zip(PosGivenArgs,GivenArgs),
Pars = lists:zip(PosParArgs,ParArgs),
{_,Args} = lists:unzip(lists:sort(Given ++ Pars)),
erlang:apply(Fun,Args);
false ->
erlang:error(badarg)
end
end;
false ->
erlang:error(badarg)
end;
_ ->
erlang:error(badarg)
end.