Counting in Erlang (how do I increment a variable?)

I figured out the Erlang: tail-recursion style outlines with functions that accept all “variables that don't change”:

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

But what is the best way to increase the counter in Erlang? In most programming languages, the way to count is to increment a variable (i.e., count += 1; ). Erlang variables do not change, so we must be creative. Fortunately, we have options ...

We can pass a counter variable with our functions and increase it with every function call. We can use the process dictionary to store the counter, and get and put - to increase it. We can use ETS, a local data warehouse for processes. We can use the counter process (!!!):

 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. 

I am sure that there are other ways, depending on the scope. What is considered "best practice" for increasing a variable in Erlang?

+6
source share
4 answers

Do not use the process dictionary.

The "normal" loop that you expect (that is, a for or do while ) is usually implemented in a recursive function in Erlang, so if you increment the "normal" counter, do this when calling the function as you show up.

Do not use the process dictionary.

If you missed, can I just indicate that you should not use the process dictionary.

+9
source

It all depends on what you use the counter for. Everything global, like the number of messages processed by the q system, should use ets: update_counter. If it is not global, I usually just include it in the parameters, as you showed.

+3
source

I think you have created a great deal, although you can deal with it a lot easier.
Consider this implementation of the for loop in Erlang:

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

So far, F is the function you want to save for I - Max values.
Isn't it easier to understand?

+3
source

The standard way to increase the counter is as in the first example. Adding a variable to the call and increasing it. I think you are confused due to lack of cycles and the possibility of updating values.

Note that:

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

compiles (more or less) the same as (in pseudocode):

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

If you want to copy the result, there are ways to do it.

Either use the list package, or accumulate the result yourself:

 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. 

Or something similar based on your example.

Edit: returned. Count as part of the return value, as this was important.

0
source

Source: https://habr.com/ru/post/983751/


All Articles