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

其他提示

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.

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

lists:foldl(
    fun(Function,Accumulator) -> Function(Accumulator) end, 
    3, 
    [
        fun(X) -> modname:add(3, X) end, 
        fun(X) -> modname:multiply(5, X) end
    ]
).
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top