Hello, I was wondering as there is no while loop in elixir, how would that look like written in Elixir:
while exists (s, m, sn) ∈ pending such that sn = next[s] do
next[s] := next[s]+1;
pending := pending \ {(s, m, sn)};
I do not really get what that algorithm does. To me it seems like you have some problem with transcription of the original one.
pending is a set of processes, next is an Array
Ahh, ok. Now I get. I can take a look later when I will be near computer
Generally you would turn the while loop into an Enum.reduce and the variables that you would have mutated get passed as part of the accumulator.
This appears to be a fragment from Algorithm 3.12 in “Introduction to Reliable and Secure Distributed Programming”.
Folks will be able to answer this question a lot more effectively if they have that context.
In that algorithm, pending
is a set of tuples {sender, message, sequence_number}
while next
is a map from sender
to the next sequence_number
expected from that sender.
The while
loop finds {sender, message_to_deliver, sequence_number}
values in pending
, and does three things:
- increments
next
forsender
- removes the tuple from
pending
- delivers
message_to_deliver
fromsender
Something like this would be my attempt:
pending = [
{1, "hello1", 2},
{1, "hello2", 1},
{2, "hello3", 1},
{2, "hello4", 2},
{2, "hello5", 4}
]
next = %{
1 => 1,
2 => 1
}
pending_transformed =
for {sender, message, sn} <- pending,
into: %{},
do: {{sender, sn}, message}
{pending_transformed, next}
|> Stream.unfold(fn
nil ->
nil
{pending_transformed, next} ->
result =
pending_transformed
|> Map.keys
|> Enum.find(fn {sender, sn} -> next[sender] == sn end)
case result do
{sender, sn} = key ->
{message, pending_transformed} = Map.pop!(pending_transformed, key)
next = Map.put(next, sender, sn + 1)
{{:send, {sender, message, sn}}, {pending_transformed, next}}
nil ->
{{:done, {pending_transformed, next}}, nil}
end
end)
|> Enum.reduce_while([], fn
{:send, msg}, acc ->
IO.inspect(msg)
{:cont, acc}
{:done, rest}, _ ->
{:halt, rest}
end)
# Output
{1, "hello2", 1}
{1, "hello1", 2}
{2, "hello3", 1}
{2, "hello4", 2}
# Result
{%{{2, 4} => "hello5"}, %{1 => 3, 2 => 3}}
Do you by any chance have that algorithm in code version ?