Unable to use function call in function guard

2019-02-12 18:01发布

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("finished printing~n")
    end.

标签: erlang
2条回答
趁早两清
2楼-- · 2019-02-12 18:51

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.

查看更多
成全新的幸福
3楼-- · 2019-02-12 18:58

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, _) ->
  .
查看更多
登录 后发表回答