Эрланг: сделать кольцо - PullRequest
       11

Эрланг: сделать кольцо

0 голосов
/ 13 ноября 2018

Я довольно новичок в 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 медленно (я думаю), и она не выглядит очень "функциональной".

Есть ли лучшее, более идиоматическое решение для этого?

Если другие функциональные программисты (не Эрланг) наткнулись на это, пожалуйста, опубликуйте свое решение - концепции те же.

Ответы [ 3 ]

0 голосов
/ 13 ноября 2018

Если вы управляете длинными списками, вы можете избежать создания промежуточного списка 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>
0 голосов
/ 14 ноября 2018

Но если нам нужно более двух процессов, я думаю, что мы должны соединить их в кольцо.

Нет.Например, предположим, что вы хотите загрузить текст 10 различных веб-страниц.Вместо отправки запроса, ожидания ответа сервера, отправки следующего запроса и т. Д. Вы можете создать отдельный процесс для каждого запроса.Каждому порожденному процессу нужен только pid основного процесса, и основной процесс собирает результаты по мере их поступления. Когда порожденный процесс получает ответ от сервера, порожденный процесс отправляет сообщение главному процессу с результатами, а затемзавершается.У порожденных процессов нет причин отправлять сообщения друг другу.Нет кольца.

Я думаю, что вряд ли вы когда-нибудь создадите кольцо процессов в вашей карьере Эрланга.

У меня проблемы с созданием элегантного решения, которое добавляет окончательный вариант.{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(.......).

Затем основной процесс может вызвать (неspawn) та же функция, которая порождается другими процессами, передавая функции последний pid, возвращенный функцией create_ring():

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

В результате главный процесс войдет втот же цикл обработки сообщений, что и в других процессах, и основной процесс будет хранить последний pid, сохраненный в переменной параметра цикла для отправки сообщений.

В erlang вы часто обнаруживаете, что во время определения функции выне сможет делать все, что вы хотите в этой функции, поэтому вам нужно вызвать другую функцию, чтобы сделать то, что вызывает у вас проблемы, и если во второй функции вы обнаружите, что вы не можете сделать все, что вам нужноделать, тогда вам нужно вызвать другую функцию и т. д. Применительно к проблеме звонка выше, я обнаружил, что init() не можетНе делайте все, что я хотел, в одной функции, поэтому я определил функцию create_ring() для решения части проблемы.

0 голосов
/ 13 ноября 2018

Используйте lists:zip с исходным списком и его «повернутой» версией:

1> L=[1,2,3].
[1,2,3]
2> lists:zip(L, tl(L) ++ [hd(L)]).
[{1,2},{2,3},{3,1}]
...