Каррирование функций Erlang

Я пытаюсь переделать все свои домашние задачи на Haskell, используя Erlang, и одна вещь, которая меня заводит, это то, как использовать список функций, которые не имеют всех своих параметров.

Пример: я пытаюсь использовать этот фолд, но не знаю, как передать функции, чтобы он работал на аккумуляторе

%%inside my module)
add(X,Y) -> X + Y.

multiply(X,Y) -> X*Y.

После этого используйте это в командной строке:

lists:foldl(fun(Function,Accumulator) -> Function(Accumulator) end, 3, [add(3),multiply(5)]).

person Kelsey Abreu    schedule 24.04.2013    source источник


Ответы (5)


В Erlang вы должны вызывать функцию, передавая все необходимые ей параметры. Но вы можете легко избежать этого, создав анонимную функцию, которая принимает только те параметры, которые вам нужны, а затем правильно вызывает вашу функцию. Если вам нужна функция, которая принимает один параметр X и вызывает функцию add(3, X), вы можете создать такую ​​анонимную функцию:

fun (X) -> add(3, X) end

Это пример для вашей задачи:

lists:foldl(fun (Function, Accumulator) -> Function(Accumulator) end, 3,
    [fun (X) -> add(3, X) end, fun (X) -> multiply(5, X) end]).
person Danil Onishchenko    schedule 24.04.2013

С точки зрения нативного Erlang нет какой-либо формы частичной оценки, как вы хотите. Вы должны будете создать свои собственные забавы, чтобы сделать это. Однако если вы используете библиотеку Erlando Monad, вы можете использовать сопоставление с образцом для ее создания. Это работает благодаря тому факту, что компилятор erlang позволяет вам играть с AST при компиляции кода, так что вы можете делать подобные классные вещи.

person Zachary K    schedule 26.04.2013

Можно довольно легко написать функцию частичного приложения, которая называется аналогично erlang:apply/3. Ему не хватает элегантности, которую вы имеете в языках, поддерживающих каррирование.

-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).
person Jan Henry Nystrom    schedule 24.04.2013

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

Использование (шум отбракован из вывода оболочки):

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"]

Полезные ресурсы:

person toraritte    schedule 20.02.2020

person    schedule
comment
Это означает, что в Erlang нет применения частичных функций (и каррирования), верно? Потому что вы используете лямбда-функции, тогда как в Haskell у нас мог бы быть список частичных прикладных(?) функций: [(+)1,(-)2,(*)3]. Или это все еще то же самое, что и приложение частичной функции? - person ichistmeinname; 24.04.2013