Erlang:打个电话

时间:2018-11-13 07:33:08

标签: functional-programming erlang

我对Erlang还是很陌生(请阅读“并行世界的软件”)。根据我的阅读,我们将两个流程链接在一起以形成一个可靠的系统。

但是,如果我们需要两个以上的过程,我认为,我们应该将它们环形连接。尽管这与我的实际问题略有关系,但是如果这是错误的话,请告诉我。

给出PIDs的列表:

[1,2,3,4,5]

我想以{My_Pid, Linked_Pid}元组的形式形成这些:

[{1,2},{2,3},{3,4},{4,5},{5,1}]

我很难创建一个优雅的解决方案来添加最终的{5,1}元组。

这是我的尝试:

% linkedPairs takes [1,2,3] and returns [{1,2},{2,3}]
linkedPairs([])         -> [];
linkedPairs([_])        -> [];
linkedPairs([X1,X2|Xs]) -> [{X1, X2} | linkedPairs([X2|Xs])].

% joinLinks takes [{1,2},{2,3}] and returns [{1,2},{2,3},{3,1}]
joinLinks([{A, _}|_]=P) ->
    {X, Y} = lists:last(P)
    P ++ [{Y, A}].

% makeRing takes [1,2,3] and returns [{1,2},{2,3},{3,1}]
makeRing(PIDs) -> joinLinks(linkedPairs(PIDs)).

当我查看自己的joinLinks函数时,我感到有些畏缩-list:last速度很慢(我认为),而且看起来不太“实用”。

是否有更好,更惯用的解决方案?

如果其他函数式程序员(非Erlang)偶然发现此问题,请发布您的解决方案-概念相同。

3 个答案:

答案 0 :(得分:3)

1> L=[1,2,3]. [1,2,3] 2> lists:zip(L, tl(L) ++ [hd(L)]). [{1,2},{2,3},{3,1}] 与原始列表及其“旋转”版本一起使用:

temp$Q <- paste(temp$Q1, temp$Q2, sep=",")
temp <- temp[,c("region", "Q")]
temp

  region        Q
1      A  ads,poi
2      B qwer,lkj
3      C zxcv,mnb

答案 1 :(得分:2)

如果要处理长列表,则可以避免使用辅助函数来创建中间列表tl(L) ++ [hd(L)]

1> L = lists:seq(1,5).
[1,2,3,4,5]
2> Link = fun Link([Last],First,Acc) -> lists:reverse([{Last,First}|Acc]);                 
              Link([X|T],First,Acc) -> Link(T,First,[{X,hd(T)}|Acc]) end.
#Fun<erl_eval.42.127694169>
3> Joinlinks = fun(List) -> Link(List,hd(List),[]) end.
#Fun<erl_eval.6.127694169>
4> Joinlinks(L).
[{1,2},{2,3},{3,4},{4,5},{5,1}]
5>

答案 2 :(得分:1)

  

但是如果我们需要两个以上的过程,我认为我们应该将它们联系起来   一圈。

不。例如,假设您要下载10个不同网页的文本。您可以为每个请求生成一个单独的进程,而不是发送请求,然后等待服务器响应,然后发送下一个请求,等等。每个产生的进程仅需要主进程的pid,并且主进程会收集传入的结果。当产生的进程从服务器获得答复时,产生的进程会向消息传递给主进程并附带结果,然后终止。产生的进程没有理由互相发送消息。没有铃声。

我想您在您的Erlang职业生涯中不可能创造出一系列流程。

  

我很难创建一个优雅的解决方案来添加最后的{5,1}元组。

您可以创建其他四个传递给它们self()的进程,每个产生的进程都不同。然后,您可以为create_ring()函数创建一个单独的分支,该分支终止递归并将最后创建的进程的pid返回到主进程:

init(N) ->
    LastPid = create_ring(....),

create_ring(0, PrevPid) -> PrevPid;
create_ring(N, PrevPid) when N > 0 ->
    Pid = spawn(?MODULE, loop, [PrevPid]),
    create_ring(.......).

然后,主进程可以调用(而不是生成)其他进程所生成的相同函数,并向该函数传递create_ring()函数返回的最后一个pid:

init(N) ->
    LastPid = create_ring(...),
    loop(LastPid).

结果,主进程将与其他进程进入相同的消息循环,并且主进程将在循环参数变量中存储最后一个pid,以将消息发送至。

在erlang中,您经常会发现在定义一个函数时,您将无法执行该函数中想要做的所有事情,因此您需要调用另一个函数来执行给您的所有操作麻烦,并且如果在第二个函数中发现自己不能做所有需要做的事情,那么就需要调用另一个函数,依此类推。应用于上面的环形问题,我发现init()无法做我想在一个函数中完成所有操作,因此我定义了create_ring()函数来处理部分问题。