2010-02-11 16 views
9

Sono nuovo in Erlang e sto provando a programmare un programma con problemi di buffer limitato. Funziona quasi, tranne che per assicurarsi che i produttori non siano troppo avanti e sovrascrivano i dati non consumati. Per gestire questo, ho deciso di provare a inserire protezioni sulla mia funzione buffer() in modo che potessi avere una versione senza ricezione usata quando il buffer è pieno, una versione senza invio usata quando il buffer è vuoto e una normale versione per il resto del tempo.Impossibile chiamare la funzione nella funzione di protezione

Il mio problema è che la protezione per la versione senza ricevitore richiede che conosca la dimensione della matrice che rappresenta il buffer, che richiede una chiamata a array:size/1. Apparentemente, Erlang non consente invocazioni di funzioni nelle guardie, il che impedisce che funzioni. C'è un modo per ovviare a questo senza cambiare la dichiarazione della funzione per il mio attore buffer?

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

risposta

13

Ci sono solo alcune funzioni che possono essere utilizzati in una guardia, vedere Guard Sequences in the Erlang manual. Puoi facilmente fare ciò che ti serve come segue:

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

Questo è bello, semplice e facilmente comprensibile. Grazie. –

+0

Ciao @Geoff, conosci un modo per confrontare due stringhe come guardia ?. es. - function when string: equals (string1, string2) -> 1. –

+0

@DenisWeerasiri Sono abbastanza sicuro che 'string: equals/2' sia lo stesso di' == 'quindi puoi semplicemente usarlo nella guardia . –

1

Come ha detto Geoff Reedy, ci sono solo poche BIF che sono consentite nelle guardie.

Ma la libreria di trasformazione parsing guardian può essere utilizzata per chiamare qualsiasi funzione nelle guardie.

Problemi correlati