2010-02-11 36 views
9

Tôi mới sử dụng Erlang và đang cố gắng lập trình một chương trình vấn đề đệm-đệm. Nó gần như hoạt động, ngoại trừ việc đảm bảo rằng các nhà sản xuất không đi quá xa phía trước và ghi đè lên dữ liệu chưa được xử lý. Để xử lý điều này, tôi quyết định thử đặt các bộ bảo vệ vào hàm buffer() để có thể có một phiên bản được sử dụng khi bộ đệm đầy, một phiên bản được gửi khi bộ đệm trống, và bình thường phiên bản cho phần còn lại của thời gian.Không thể sử dụng chức năng gọi trong chức năng bảo vệ

Vấn đề của tôi là bảo vệ cho phiên bản người nhận ít yêu cầu tôi biết kích thước của mảng đại diện cho bộ đệm, yêu cầu gọi đến array:size/1. Rõ ràng, Erlang không cho phép các lời gọi hàm trong bảo vệ, điều này ngăn cản việc này hoạt động. Có cách nào để làm việc xung quanh điều này mà không thay đổi khai báo hàm cho diễn viên đệm của tôi?

%% 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. 

Trả lời

13

Chỉ có một số chức năng nhất định có thể được sử dụng trong bảo vệ, xem Guard Sequences in the Erlang manual. Bạn có thể dễ dàng thực hiện những gì bạn cần như sau:

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, _) -> 
    . 
+0

Thật tuyệt, đơn giản và dễ hiểu. Cảm ơn. –

+0

Xin chào @Geoff, Bạn có biết cách so sánh hai chuỗi như một người bảo vệ không ?. ví dụ - chức năng khi chuỗi: bằng (string1, string2) -> 1. –

+0

@DenisWeerasiri Tôi khá chắc chắn rằng 'chuỗi: bằng/2' chỉ là giống như' == 'vì vậy bạn chỉ có thể sử dụng trong bảo vệ . –

1

Vì Geoff Reedy đã đề cập chỉ có một vài BIF được cho phép trong bảo vệ.

Nhưng thư viện chuyển đổi phân tích guardian có thể được sử dụng để gọi bất kỳ chức năng nào trong bộ phận bảo vệ.

Các vấn đề liên quan