2010-02-11 9 views
9

Soy nuevo en Erlang y estoy tratando de programar un programa de problema de buffer delimitado. Está casi funcionando, excepto para asegurarse de que los productores no se excedan y sobrescriban datos no consumidos. Para manejar esto, decidí tratar de poner guardias en mi función buffer() para poder tener una versión sin recepción utilizada cuando el buffer está lleno, una versión sin enviar usada cuando el buffer está vacío, y una versión normal versión por el resto del tiempo.No se puede usar la función de llamada en la función de protección

Mi problema es que la protección para la versión sin receptor me exige conocer el tamaño de la matriz que representa el búfer, que requiere una llamada al array:size/1. Aparentemente, Erlang no permite invocaciones de funciones en guardias, lo que impide que esto funcione. ¿Hay alguna forma de evitar esto sin cambiar la declaración de función para mi actor de búfer?

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

Respuesta

13

Sólo hay ciertas funciones que se pueden utilizar en una guardia, ver Guard Sequences in the Erlang manual. Usted puede hacer fácilmente lo que necesita de la siguiente manera:

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

Eso es bueno, simple y fácil de entender. Gracias. –

+0

Hola @Geoff, ¿conoces una manera de comparar dos cuerdas como guardia? por ejemplo, función cuando string: igual (cadena1, cadena2) -> 1. –

+0

@DenisWeerasiri Estoy bastante seguro de que 'string: igual/2' es lo mismo que' == 'así que puedes usar eso en la guardia . –

1

como Geoff Reedy ha mencionado que hay sólo unos pocos BIFS que se permiten en guardias.

Pero la biblioteca de transformación parse guardian se puede usar para llamar a cualquier función en guardias.

Cuestiones relacionadas