Unable to use function call in function guard
I'm new to Erlang and am trying to program a bounded-buffer problem program. It is almost working, except for making sure the producers don't get too far ahead and overwrite unconsumed data. To handle this, I decided to try putting guards on my buffer() function so that I could have a version w/o receive used when the buffer is full, a version w/o send used when the buffer is empty, and a normal version for the rest of the time.
My problem is that the guard for the receiver-less version requires me to know the size of the array representing the buffer, which requires a call to array:size/1
. Apparently, Erlang does not allow function invocations in guards, which prevents this from working. Is there some way to work around this without changing the function declaration for my buffer actor?
%% buffer: array num num
%% A process that holds the shared buffer for the producers and consumers
buffer(Buf, NextWrite, NextRead) when NextWrite == NextRead ->
io:format(" * ~w, ~w, ~w~n", [array:to_list(Buf), NextRead, NextWrite]),
receive
{enqueue, Reply_Pid, Num} ->
io:format("~w: > ~w~n", [Reply_Pid, Num]),
buffer(array:set(NextWrite rem array:size(Buf), Num, Buf), NextWrite + 1, NextRead);
finish ->
io:format("finished printing~n")
end;
buffer(Buf, NextWrite, NextRead) when (NextWrite - NextRead) == array:size(Buf) ->
io:format(" * ~w, ~w, ~w~n", [array:to_list(Buf), NextRead, NextWrite]),
receive
{dequeue, Reply_Pid} ->
io:format("~w: < ~w~n", [Reply_Pid, array:get(NextRead rem array:size(Buf), Buf)]),
Reply_Pid ! {reply, array:get(NextRead rem array:size(Buf), Buf)},
buffer(Buf, NextWrite, NextRead + 1);
finish ->
io:format("finished printing~n")
end;
buffer(Buf, NextWrite, NextRead) ->
io:format(" * ~w, ~w, ~w~n", [array:to_list(Buf), NextRead, NextWrite]),
receive
{dequeue, Reply_Pid} ->
io:format("~w: < ~w~n", [Reply_Pid, array:get(NextRead rem array:size(Buf), Buf)]),
Reply_Pid ! {reply, array:get(NextRead rem array:size(Buf), Buf)},
buffer(Buf, NextWrite, NextRead + 1);
{enqueue, Reply_Pid, Num} ->
io:format("~w: > ~w~n", [Reply_Pid, Num]),
buffer(array:set(NextWrite rem array:size(Buf), Num, Buf), NextWrite + 1, NextRead);
finish ->
io:format(开发者_StackOverflow中文版"finished printing~n")
end.
There are only certain functions that can be used in a guard, see Guard Sequences in the Erlang manual. You can easily do what you need as follows:
buffer(Buf, NextWrite, NextRead) -> buffer(Buf, NextWrite, NextRead, array:size(Buf)).
buffer(Buf, NextWrite, NextRead, _) when NextWrite == NextRead ->
;
buffer(Buf, NextWrite, NextRead, BufSize) when (NextWrite - NextRead) == BufSize ->
;
buffer(Buf, NextWrite, NextRead, _) ->
.
As Geoff Reedy has mentioned there are only few BIFS that are allowed in guards.
But the guardian parse transform library can be used to call any function in guards.
精彩评论