【问题标题】:Currying Functions Erlang柯里化函数 Erlang
【发布时间】:2020-02-21 05:10:56
【问题描述】:

我正在尝试使用 Erlang 重做我所有的 Haskell 作业问题,而让我受益匪浅的一件事是如何使用没有所有参数的函数列表。

示例:我正在尝试使用此折叠,但我不知道如何传入函数以便它在累加器上运行

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

【问题讨论】:

    标签: haskell erlang currying fold


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      就本机 Erlang 而言,没有您想要的任何形式的部分评估。你将不得不创造自己的乐趣来做到这一点。但是,如果您使用Erlando Monad Library,那么您可以使用模式匹配来创建它。它的工作原理是 erlang 编译器允许你在编译代码时使用 AST,这样你就可以做这样很酷的事情。

      【讨论】:

        【解决方案3】:

        人们可以相当容易地编写一个类似于 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).
        

        【讨论】:

          【解决方案4】:
          -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]).
          

          用法(从 shell 输出中剔除的噪音):

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

          有用的资源:

          【讨论】:

            【解决方案5】:
            lists:foldl(
                fun(Function,Accumulator) -> Function(Accumulator) end, 
                3, 
                [
                    fun(X) -> modname:add(3, X) end, 
                    fun(X) -> modname:multiply(5, X) end
                ]
            ).
            

            【讨论】:

            • 这意味着 Erlang 中没有偏函数应用程序(也没有柯里化),对吧?因为你使用了 lambda 函数,而在 Haskell 中我们可以有一个部分应用(?)函数的列表:[(+)1,(-)2,(*)3]。还是还是和偏函数应用一样?
            猜你喜欢
            • 2016-01-01
            • 2021-02-07
            • 2012-10-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-11-16
            • 2013-10-04
            • 1970-01-01
            相关资源
            最近更新 更多