I'm trying to redo all of my Haskell homework problems using Erlang, and one thing that gets me is how to use a list of functions that don't have all of their parameters.
Example: I'm trying to use this fold, but I don't know how to pass in the functions so that it operates on the accumulator
%%inside my module)
add(X,Y) -> X + Y.
multiply(X,Y) -> X*Y.
Afterwards using this in the command line:
lists:foldl(fun(Function,Accumulator) -> Function(Accumulator) end, 3, [add(3),multiply(5)]).
In terms of native Erlang there is not any form of partial evaluation like you want. You will have to create your own fun's to do it. However if you use the Erlando Monad Library then you can use pattern matching to create it. It works by the fact that the erlang compiler lets you play with the AST on compiling code so you can do cool stuff like this.
-module(f).
-export([curry/1]).
curry(AnonymousFun) ->
{arity, Arity} =
erlang:fun_info(AnonymousFun, arity),
do_curry(AnonymousFun, Arity, [[], [], []]).
do_curry(Fun, 0, [Fronts, Middle, Ends] = X) ->
% Fronts ++ Middle ++ ")" ++ Ends;
[F, M, E] =
lists:map(fun(L) -> string:join(L, "") end, X),
Fstring =
F ++ "Run(" ++ string:trim(M, trailing, ",") ++ ")" ++ E,
{ok, Tokens, _} =
erl_scan:string(Fstring ++ "."),
{ok, Parsed} =
erl_parse:parse_exprs(Tokens),
FunBinding =
erl_eval:add_binding(
'Run',
Fun,
erl_eval:new_bindings()
),
{value ,CurriedFun, _} =
erl_eval:exprs(Parsed, FunBinding),
CurriedFun;
do_curry(Fun, Arity, [Fronts, Middle, Ends]) ->
VarName = [64 + Arity],
NewFronts = ["fun(" ++ VarName ++ ") -> " | Fronts] ,
NewMiddle = [VarName ++ ","|Middle],
NewEnds = [" end"|Ends],
do_curry(Fun, Arity-1, [NewFronts, NewMiddle, NewEnds]).
Usage (noise culled from shell output):
72> c("./f") % If `f.erl` is in the current dir that is.
73> F = f:curry(fun(A,B,C) -> A + B + C end).
74> F(1).
75> G = F(1).
76> G(2).
77> H = G(2).
78> H(3).
6
79> I = (F(1))(2).
80> I(3).
6
82> F2 = mtest:curry(fun erlang:'++'/2).
83> F2("lofa").
84> (F2("lofa"))("miez").
"lofamiez"
85> ((f:curry(fun lists:map/2))((f:curry(fun filename:join/2))("dir")))(["a_file", "b_file"]).
["dir/a_file","dir/b_file"]
Useful resources:
In Erlang you must call function passing all parameters it requires. But you can easily avoid it by creating an anonymous function which takes only those parameters you need and then calls your function rightly. If you need a function which takes one parameter X and calls function add(3, X) you can create an anonymous function like that:
fun (X) -> add(3, X) end
This is an example for your task:
lists:foldl(fun (Function, Accumulator) -> Function(Accumulator) end, 3,
[fun (X) -> add(3, X) end, fun (X) -> multiply(5, X) end]).
One can fairly easily write a partial application function which is called analogous way to erlang:apply/3. It lacks the elegance you have in languages that support currying.
-module(partial).
-export([apply/4]).
apply(Module, Name, Arity, Args) when length(Args) < Arity ->
Left = Arity - length(Args),
fun(Args1) when length(Args1) < Left ->
fun(Args2) ->
apply(Module, Name, Arity, Args2 ++ Args1 ++ Args)
end;
(Args1) when length(Args1) > Left ->
erlang:error(badarg);
(Args1) ->
erlang:apply(Module, Name, Args1 ++ Args)
end;
apply(_, _, Arity, Args) when length(Args) > Arity ->
erlang:error(badarg);
apply(Module, Name, _, Args) ->
erlang:apply(Module, Name, Args).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With