

 This page uses content from Wikipedia. The original article was at Currying. The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance)



Task

Create a simple demonstrative example of Currying in a specific language.

Add any historic details as to how the feature made its way into the language.




 
-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.
 