Erlang: Make a ring
I'm quite new to Erlang (Reading through "Software for a Concurrent World"). From what I've read, we link two processes together to form a reliable system.
But if we need more than two process, I think we should connect them in a ring. Although this is slightly tangential to my actual question, please let me know if this is incorrect.
Given a list of PIDs
:
[1,2,3,4,5]
I want to form these in a ring of My_Pid, Linked_Pid
tuples:
[1,2,2,3,3,4,4,5,5,1]
I have trouble creating an elegant solution that adds the final 5,1
tuple.
Here is my attempt:
% 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)).
I cringe when looking at my joinLinks
function - list:last
is slow (I think), and it doesn't look very "functional".
Is there a better, more idiomatic solution to this?
If other functional programmers (non-Erlang) stumble upon this, please post your solution - the concepts are the same.
functional-programming erlang
add a comment |
I'm quite new to Erlang (Reading through "Software for a Concurrent World"). From what I've read, we link two processes together to form a reliable system.
But if we need more than two process, I think we should connect them in a ring. Although this is slightly tangential to my actual question, please let me know if this is incorrect.
Given a list of PIDs
:
[1,2,3,4,5]
I want to form these in a ring of My_Pid, Linked_Pid
tuples:
[1,2,2,3,3,4,4,5,5,1]
I have trouble creating an elegant solution that adds the final 5,1
tuple.
Here is my attempt:
% 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)).
I cringe when looking at my joinLinks
function - list:last
is slow (I think), and it doesn't look very "functional".
Is there a better, more idiomatic solution to this?
If other functional programmers (non-Erlang) stumble upon this, please post your solution - the concepts are the same.
functional-programming erlang
add a comment |
I'm quite new to Erlang (Reading through "Software for a Concurrent World"). From what I've read, we link two processes together to form a reliable system.
But if we need more than two process, I think we should connect them in a ring. Although this is slightly tangential to my actual question, please let me know if this is incorrect.
Given a list of PIDs
:
[1,2,3,4,5]
I want to form these in a ring of My_Pid, Linked_Pid
tuples:
[1,2,2,3,3,4,4,5,5,1]
I have trouble creating an elegant solution that adds the final 5,1
tuple.
Here is my attempt:
% 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)).
I cringe when looking at my joinLinks
function - list:last
is slow (I think), and it doesn't look very "functional".
Is there a better, more idiomatic solution to this?
If other functional programmers (non-Erlang) stumble upon this, please post your solution - the concepts are the same.
functional-programming erlang
I'm quite new to Erlang (Reading through "Software for a Concurrent World"). From what I've read, we link two processes together to form a reliable system.
But if we need more than two process, I think we should connect them in a ring. Although this is slightly tangential to my actual question, please let me know if this is incorrect.
Given a list of PIDs
:
[1,2,3,4,5]
I want to form these in a ring of My_Pid, Linked_Pid
tuples:
[1,2,2,3,3,4,4,5,5,1]
I have trouble creating an elegant solution that adds the final 5,1
tuple.
Here is my attempt:
% 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)).
I cringe when looking at my joinLinks
function - list:last
is slow (I think), and it doesn't look very "functional".
Is there a better, more idiomatic solution to this?
If other functional programmers (non-Erlang) stumble upon this, please post your solution - the concepts are the same.
functional-programming erlang
functional-programming erlang
edited Nov 13 '18 at 22:00
Justin Wood
7,05822037
7,05822037
asked Nov 13 '18 at 7:33
hazhaz
320422
320422
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
But if we need more than two process, I think we should connect them
in a ring.
No. For instance, suppose you want to download the text of 10 different web pages. Instead of sending a request, then waiting for the server to respond, then sending the next request, etc., you can spawn a separate process for each request. Each spawned process only needs the pid of the main process, and the main process collects the results as they come in. When a spawned process gets a reply from a server, the spawned process sends a message to the main process with the results, then terminates. The spawned processes have no reason to send messages to each other. No ring.
I would guess that it is unlikely that you will ever create a ring of processes in your erlang career.
I have trouble creating an elegant solution that adds the final 5,1 tuple.
You can create the four other processes passing them self()
, which will be different for each spawned process. Then, you can create a separate branch of your create_ring()
function that terminates the recursion and returns the pid of the last created process to the main process:
init(N) ->
LastPid = create_ring(....),
create_ring(0, PrevPid) -> PrevPid;
create_ring(N, PrevPid) when N > 0 ->
Pid = spawn(?MODULE, loop, [PrevPid]),
create_ring(.......).
Then, the main process can call (not spawn) the same function that is being spawned by the other processes, passing the function the last pid that was returned by the create_ring()
function:
init(N) ->
LastPid = create_ring(...),
loop(LastPid).
As a result, the main process will enter into the same message loop as the other processes, and the main process will have the last pid stored in the loop parameter variable to send messages to.
In erlang, you will often find that while you are defining a function, you won't be able to do everything that you want in that function, so you need to call another function to do whatever it is that is giving you trouble, and if in the second function you find you can't do everything you need to do, then you need to call another function, etc. Applied to the ring problem above, I found that init()
couldn't do everything I wanted in one function, so I defined the create_ring()
function to handle part of the problem.
add a comment |
Use lists:zip
with the original list and its 'rotated' version:
1> L=[1,2,3].
[1,2,3]
2> lists:zip(L, tl(L) ++ [hd(L)]).
[1,2,2,3,3,1]
Ah, that's a great way to rotate it – I was searching for arotate
function. Cheers!
– haz
Nov 13 '18 at 7:44
add a comment |
If you are manipulating long lists, you can avoid the creation of the intermediary list tl(L) ++ [hd(L)]
using an helper function:
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>
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53275962%2ferlang-make-a-ring%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
But if we need more than two process, I think we should connect them
in a ring.
No. For instance, suppose you want to download the text of 10 different web pages. Instead of sending a request, then waiting for the server to respond, then sending the next request, etc., you can spawn a separate process for each request. Each spawned process only needs the pid of the main process, and the main process collects the results as they come in. When a spawned process gets a reply from a server, the spawned process sends a message to the main process with the results, then terminates. The spawned processes have no reason to send messages to each other. No ring.
I would guess that it is unlikely that you will ever create a ring of processes in your erlang career.
I have trouble creating an elegant solution that adds the final 5,1 tuple.
You can create the four other processes passing them self()
, which will be different for each spawned process. Then, you can create a separate branch of your create_ring()
function that terminates the recursion and returns the pid of the last created process to the main process:
init(N) ->
LastPid = create_ring(....),
create_ring(0, PrevPid) -> PrevPid;
create_ring(N, PrevPid) when N > 0 ->
Pid = spawn(?MODULE, loop, [PrevPid]),
create_ring(.......).
Then, the main process can call (not spawn) the same function that is being spawned by the other processes, passing the function the last pid that was returned by the create_ring()
function:
init(N) ->
LastPid = create_ring(...),
loop(LastPid).
As a result, the main process will enter into the same message loop as the other processes, and the main process will have the last pid stored in the loop parameter variable to send messages to.
In erlang, you will often find that while you are defining a function, you won't be able to do everything that you want in that function, so you need to call another function to do whatever it is that is giving you trouble, and if in the second function you find you can't do everything you need to do, then you need to call another function, etc. Applied to the ring problem above, I found that init()
couldn't do everything I wanted in one function, so I defined the create_ring()
function to handle part of the problem.
add a comment |
But if we need more than two process, I think we should connect them
in a ring.
No. For instance, suppose you want to download the text of 10 different web pages. Instead of sending a request, then waiting for the server to respond, then sending the next request, etc., you can spawn a separate process for each request. Each spawned process only needs the pid of the main process, and the main process collects the results as they come in. When a spawned process gets a reply from a server, the spawned process sends a message to the main process with the results, then terminates. The spawned processes have no reason to send messages to each other. No ring.
I would guess that it is unlikely that you will ever create a ring of processes in your erlang career.
I have trouble creating an elegant solution that adds the final 5,1 tuple.
You can create the four other processes passing them self()
, which will be different for each spawned process. Then, you can create a separate branch of your create_ring()
function that terminates the recursion and returns the pid of the last created process to the main process:
init(N) ->
LastPid = create_ring(....),
create_ring(0, PrevPid) -> PrevPid;
create_ring(N, PrevPid) when N > 0 ->
Pid = spawn(?MODULE, loop, [PrevPid]),
create_ring(.......).
Then, the main process can call (not spawn) the same function that is being spawned by the other processes, passing the function the last pid that was returned by the create_ring()
function:
init(N) ->
LastPid = create_ring(...),
loop(LastPid).
As a result, the main process will enter into the same message loop as the other processes, and the main process will have the last pid stored in the loop parameter variable to send messages to.
In erlang, you will often find that while you are defining a function, you won't be able to do everything that you want in that function, so you need to call another function to do whatever it is that is giving you trouble, and if in the second function you find you can't do everything you need to do, then you need to call another function, etc. Applied to the ring problem above, I found that init()
couldn't do everything I wanted in one function, so I defined the create_ring()
function to handle part of the problem.
add a comment |
But if we need more than two process, I think we should connect them
in a ring.
No. For instance, suppose you want to download the text of 10 different web pages. Instead of sending a request, then waiting for the server to respond, then sending the next request, etc., you can spawn a separate process for each request. Each spawned process only needs the pid of the main process, and the main process collects the results as they come in. When a spawned process gets a reply from a server, the spawned process sends a message to the main process with the results, then terminates. The spawned processes have no reason to send messages to each other. No ring.
I would guess that it is unlikely that you will ever create a ring of processes in your erlang career.
I have trouble creating an elegant solution that adds the final 5,1 tuple.
You can create the four other processes passing them self()
, which will be different for each spawned process. Then, you can create a separate branch of your create_ring()
function that terminates the recursion and returns the pid of the last created process to the main process:
init(N) ->
LastPid = create_ring(....),
create_ring(0, PrevPid) -> PrevPid;
create_ring(N, PrevPid) when N > 0 ->
Pid = spawn(?MODULE, loop, [PrevPid]),
create_ring(.......).
Then, the main process can call (not spawn) the same function that is being spawned by the other processes, passing the function the last pid that was returned by the create_ring()
function:
init(N) ->
LastPid = create_ring(...),
loop(LastPid).
As a result, the main process will enter into the same message loop as the other processes, and the main process will have the last pid stored in the loop parameter variable to send messages to.
In erlang, you will often find that while you are defining a function, you won't be able to do everything that you want in that function, so you need to call another function to do whatever it is that is giving you trouble, and if in the second function you find you can't do everything you need to do, then you need to call another function, etc. Applied to the ring problem above, I found that init()
couldn't do everything I wanted in one function, so I defined the create_ring()
function to handle part of the problem.
But if we need more than two process, I think we should connect them
in a ring.
No. For instance, suppose you want to download the text of 10 different web pages. Instead of sending a request, then waiting for the server to respond, then sending the next request, etc., you can spawn a separate process for each request. Each spawned process only needs the pid of the main process, and the main process collects the results as they come in. When a spawned process gets a reply from a server, the spawned process sends a message to the main process with the results, then terminates. The spawned processes have no reason to send messages to each other. No ring.
I would guess that it is unlikely that you will ever create a ring of processes in your erlang career.
I have trouble creating an elegant solution that adds the final 5,1 tuple.
You can create the four other processes passing them self()
, which will be different for each spawned process. Then, you can create a separate branch of your create_ring()
function that terminates the recursion and returns the pid of the last created process to the main process:
init(N) ->
LastPid = create_ring(....),
create_ring(0, PrevPid) -> PrevPid;
create_ring(N, PrevPid) when N > 0 ->
Pid = spawn(?MODULE, loop, [PrevPid]),
create_ring(.......).
Then, the main process can call (not spawn) the same function that is being spawned by the other processes, passing the function the last pid that was returned by the create_ring()
function:
init(N) ->
LastPid = create_ring(...),
loop(LastPid).
As a result, the main process will enter into the same message loop as the other processes, and the main process will have the last pid stored in the loop parameter variable to send messages to.
In erlang, you will often find that while you are defining a function, you won't be able to do everything that you want in that function, so you need to call another function to do whatever it is that is giving you trouble, and if in the second function you find you can't do everything you need to do, then you need to call another function, etc. Applied to the ring problem above, I found that init()
couldn't do everything I wanted in one function, so I defined the create_ring()
function to handle part of the problem.
edited Nov 14 '18 at 0:19
answered Nov 13 '18 at 23:17
7stud7stud
29.4k96083
29.4k96083
add a comment |
add a comment |
Use lists:zip
with the original list and its 'rotated' version:
1> L=[1,2,3].
[1,2,3]
2> lists:zip(L, tl(L) ++ [hd(L)]).
[1,2,2,3,3,1]
Ah, that's a great way to rotate it – I was searching for arotate
function. Cheers!
– haz
Nov 13 '18 at 7:44
add a comment |
Use lists:zip
with the original list and its 'rotated' version:
1> L=[1,2,3].
[1,2,3]
2> lists:zip(L, tl(L) ++ [hd(L)]).
[1,2,2,3,3,1]
Ah, that's a great way to rotate it – I was searching for arotate
function. Cheers!
– haz
Nov 13 '18 at 7:44
add a comment |
Use lists:zip
with the original list and its 'rotated' version:
1> L=[1,2,3].
[1,2,3]
2> lists:zip(L, tl(L) ++ [hd(L)]).
[1,2,2,3,3,1]
Use lists:zip
with the original list and its 'rotated' version:
1> L=[1,2,3].
[1,2,3]
2> lists:zip(L, tl(L) ++ [hd(L)]).
[1,2,2,3,3,1]
answered Nov 13 '18 at 7:36
pdexterpdexter
696614
696614
Ah, that's a great way to rotate it – I was searching for arotate
function. Cheers!
– haz
Nov 13 '18 at 7:44
add a comment |
Ah, that's a great way to rotate it – I was searching for arotate
function. Cheers!
– haz
Nov 13 '18 at 7:44
Ah, that's a great way to rotate it – I was searching for a
rotate
function. Cheers!– haz
Nov 13 '18 at 7:44
Ah, that's a great way to rotate it – I was searching for a
rotate
function. Cheers!– haz
Nov 13 '18 at 7:44
add a comment |
If you are manipulating long lists, you can avoid the creation of the intermediary list tl(L) ++ [hd(L)]
using an helper function:
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>
add a comment |
If you are manipulating long lists, you can avoid the creation of the intermediary list tl(L) ++ [hd(L)]
using an helper function:
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>
add a comment |
If you are manipulating long lists, you can avoid the creation of the intermediary list tl(L) ++ [hd(L)]
using an helper function:
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>
If you are manipulating long lists, you can avoid the creation of the intermediary list tl(L) ++ [hd(L)]
using an helper function:
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>
answered Nov 13 '18 at 12:45
PascalPascal
11.6k11425
11.6k11425
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53275962%2ferlang-make-a-ring%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown