2010-09-29 19 views
5

que he descubierto el estilo de Erlang bucles: cola de recursión con las funciones que toman todas las "variables que no varían":Contar en Erlang (? ¿Cómo incrementar una variable)

%% does something, 80 bytes at a time 
loop(Line, File) -> loop(Line, File, 0). 
loop(Line, File, Count) -> 
    do_something(Line, Count), 
    case file:read(File, 80) of 
     {ok, Line2} -> loop(Line2, File, Count + 1); 
     eof -> file:close(File); 
     {error, Reason} -> {error, Reason} 
    end. 

Pero, ¿cuál es la mejor manera de incrementar un contador en Erlang? En la mayoría de los lenguajes de programación, la forma en que cuenta las cosas es mediante el incremento de una variable (es decir, count += 1;). Las variables de Erlang no varían, por lo que debemos ser creativos. Afortunadamente, tenemos opciones ...

Podemos pasar una variable de contador con nuestras funciones, y aumentarla con cada llamada de función. Podemos usar el diccionario de proceso para almacenar un conteo, y get y put para incrementarlo. Podemos usar ETS, el almacenamiento de datos local para procesos. Podemos usar un proceso de contador (!!!):

loop(Count) ->        
    receive         
     { incr } -> 
      loop(Count + 1);    
     { report, To } ->      
      To ! { count, Count },    
      loop(Count)       
    end.          

incr(Counter) -> 
    Counter ! { incr }. 

get_count(Counter) ->  
    Counter ! { report, self() }, 
    receive 
     { count, Count } -> Count 
    end. 

Estoy seguro de que hay otras maneras también, dependiendo del alcance. ¿Qué se considera "mejor práctica" para incrementar una variable en Erlang?

+0

Esta pregunta no es demasiado significativa sin un caso de uso. Puedes hacer 'lists: foldl' para contar cosas en una lista (o' filter' + 'length'). Si está contando las llamadas 'gen_server', puede hacer eso fácilmente con el estado de su servidor. – Dustin

+0

Ya me falta PHP ... estática $ i; $ i ++; – Rolf

Respuesta

3

Todo depende de para qué uses el contador. Cualquier cosa global como la cantidad de mensajes manejados por el sistema q debería usar ets: update_counter. Si no es global, generalmente solo lo incluyo en los parámetros que mostró.

9

No utilice el diccionario de proceso.

El bucle 'normal' que está esperando (es decir, un bucle for o una do while) se implementa normalmente en una función recursiva en Erlang por lo que si usted está incrementando un contador 'normal' lo hacen en la función de llamadas como demuestras arriba arriba

No utilice el diccionario de proceso.

En caso de que se haya perdido, ¿puedo señalar que no debe usar el diccionario de proceso?

+3

Además, no use el diccionario de proceso. –

+2

Sin embargo, curiosamente, el diccionario de procesos se usa en casi todas las aplicaciones de la distribución Erlang/OTP. Me gusta 'inets'. O 'orber'. O 'docbuilder'. O 'ic'. O 'megaco'. O 'tv'. O 'cosNotification'. O 'eunit'. O 'reltool'. O 'compilador'. O 'erts'. O 'test_server'. O 'appmon'. O 'ssh'. O 'depurador'. O 'kernel'. O 'gs'. O 'os_mon'. O 'pman'. O 'stdlib'. O 'percepto'. O 'xmerl'. O 'asn1'. O 'mnesia'. O 'common_test'. O 'parsetools'. O 'dializador'. O ... Sería más fácil creer el meme del "diccionario sin proceso" si la comunidad se quedaba en el mensaje. –

+3

La regla general es que "si se pregunta si debe usar el diccionario de proceso, no debe usarlo" y "sabrá cuando lo necesite". Para ser justos, si bien hay usos de diccionario de procesos válidos, la mayoría de ellos no tienen que ver con 'incrementar las variables', sino más bien 'almacenar los metadatos del proceso', hasta donde yo sé. –

0

La forma estándar de incrementar un contador es como en su primer ejemplo. Agregando una variable a la llamada e incrementándola. Creo que te confundes por la falta de bucles for y la posibilidad de actualizar valores.

Tenga en cuenta que:

repeat(Times) when Times >= 0 -> repeat(0, Times). 

repeat(Times, Times) -> done; 
repeat(N, Times) -> 
    do_a_side_effect, 
    repeat(N + 1, Times). 

compila a (más o menos) lo mismo que (en pseudocódigo):

repeat(Times) -> 
    while (N < Times) { 
    do_a_side_effect 
    N++ 
    } 
    return done 

Si desea acumular el resultado, hay maneras de hacer eso tambien.

utilizar el paquete de listas o acumular el resultado mismo:

loop(File) -> 
    {ok, Fd} = file:open(File), 
    loop(Fd, 0, []). 

loop(Fd, Count, Acc) -> 
    case file:read(Fd, 80) of 
    {ok, Line} -> 
     Result = do_something(Line, Count), 
     loop(Fd, Count + 1, [Result | Acc]); 
    eof -> 
     file:close(File), 
     {Count, lists:reverse(Acc)}; 
    {error, Reason} -> {error, Reason} 
    end. 

o algo similar sobre la base de su ejemplo.

Editar: devolvió el recuento como parte del valor de retorno también, ya que parecía ser importante.

2

Creo que ha creado un gran problema, mientras que puede manejarlo mucho más fácil.
considerar esta aplicación por un bucle en Erlang:

for(Max, Max, F) -> [ F(Max) ]; 
for(I, Max, F) -> [ F(I) | for(I+1, Max, F) ]. 

Mientras F es la función que desea guardarlo de resultados para los valores I a Max.
¿No es eso más fácil de entender?

Cuestiones relacionadas