【问题标题】:Erlang: serial implementation of accumulatorErlang:累加器的串行实现
【发布时间】:2018-09-27 15:06:17
【问题描述】:

我正在尝试创建一个方法,该方法采用关联和交换运算符以及值列表,然后通过将运算符应用于列表中的值来返回答案。

以下两个示例表示输入/输出应该是什么样子。

示例 1

Input: sum(fun(A,B) -> A+B end, [2,6,7,10,12]).

Output: 37

示例 2

Input: sum(fun (A,B) -> A++B end , ["C", "D", "E"]).

Output: "CDE"

这是我目前正在使用的代码。

-module(tester).
-compile(export_all).

sum(Func, Data, Acc) ->
    lists:foldr(Func, Acc, Data).

此代码产生了正确的结果,但是,我试图找出两个问题来解决问题。

(1) 为了使该代码能够工作,它需要在命令行语句的末尾包含一个空列表。换句话说,如果我输入上面的输入(如示例中),它会出错,因为我没有按以下方式编写:

12> tester:sum(fun(X, Acc) -> X+Acc end, [2,6,7,10,12], 0).

如果没有上述示例中的空列表,我将如何实现它并获得相同的结果?

(2) 另外,如果没有列表函数,或者以更串行的方式,代码将如何实现?

【问题讨论】:

    标签: erlang


    【解决方案1】:

    如果没有上面示例中的空列表,我将如何实现它并获得相同的结果?

    假设列表总是有一个元素(如果没有这个假设,您实际上无法做到这一点),您可以从列表中提取第一个元素并将其作为初始累加器传递。您需要切换到foldl 才能有效地执行此操作。 (使用foldr,您基本上需要复制列表以删除最后一个元素。)

    sum(Func, [X | Xs]) ->
      lists:foldl(fun (A, B) -> Func(B, A) end, X, Xs).
    
    1> a:sum(fun(A,B) -> A+B end, [2,6,7,10,12]).
    37
    2> a:sum(fun (A,B) -> A++B end , ["C", "D", "E"]).
    "CDE"
    

    另外,如果没有 list 函数,代码将如何实现,或者以更串行的方式实现?

    这是一个使用递归和模式匹配的简单实现:

    sum2(Func, [X | Xs]) ->
      sum2(Func, Xs, X).
    
    sum2(Func, [], Acc) ->
      Acc;
    sum2(Func, [X | Xs], Acc) ->
      sum2(Func, Xs, Func(Acc, X)).
    

    我们定义了两个版本的函数。第一个提取头部并将其用作初始累加器。第二个,具有 arity 3,基本上完成了 lists 中的折叠功能。

    【讨论】:

    • 非常感谢您的帮助。这行得通。下一步是尝试弄清楚如何实现同一个累加器的并行版本。我正在考虑使用与合并排序相同的想法来完成此操作,然后仅生成单独的进程来对部分进行排序,然后合并它们等。您知道解决此问题的更简单方法吗?
    • 您可以尝试在列表中使用rpc:pmap/3,然后合并其结果。不确定这是否是您要查找的内容,但可能值得检查。
    【解决方案2】:

    在研究了一段时间后,这是我的解决方案。我留下了一些关于我所做工作的大致想法的内容,但还有很多话要说。

    -module(erlang2).
    -compile(export_all).
    -export([reduce/2]).
    
    reduce(Func, List) ->
        reduce(root, Func, List).
    
    %When done send results to Parent
    reduce(Parent, _, [A]) -> 
        %send to parent 
        Parent ! { self(), A}; 
    
       %I tried this at first to take care of one el in list, but it didn't work
       %length ([]) ->
       % Parent !   {self(), A};
    
    %get contents of list, apply function and store in Parent
    reduce(Parent, Func, List) ->
                { Left, Right } = lists:split(trunc(length(List)/2), List),
                Me = self(),
                %io:format("Splitting in two~n"),
                Pl = spawn(fun() -> reduce(Me, Func, Left) end),
                Pr = spawn(fun() -> reduce(Me, Func, Right) end),
                %merge results in parent and call Func on final left and right halves
                combine(Parent, Func,[Pl, Pr]).
    
    %merge pl and pl and combine in parent
    combine(Parent, Func, [Pl, Pr]) ->
        %wait for processes to complete (using receive) and then send to Parent
        receive
            { Pl, Sorted } -> combine(Parent, Func, Pr, Sorted);
            { Pr, Sorted } -> combine(Parent, Func, Pl, Sorted)
        end.
    
    combine(Parent, Func, P, List) ->
        %wait and store in results and then call ! to send
        receive
            { P, Sorted } ->
                Results = Func(Sorted, List),
                case Parent of
                    root ->
                        Results;
                    %send results to parent
                    _ -> Parent ! {self(), Results}
                end
        end.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-12
      • 1970-01-01
      • 2021-10-13
      • 1970-01-01
      相关资源
      最近更新 更多