Подсчет в Эрланге (как мне увеличить переменную?) - PullRequest
6 голосов
/ 29 сентября 2010

Я разобрался в циклах в стиле Эрланга: хвостовая рекурсия с функциями, которые принимают все «переменные, которые не меняются»:

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

Но, каков наилучший способ увеличениясчетчик в Эрланге?В большинстве языков программирования подсчет вещей происходит путем увеличения переменной (т. Е. count += 1;).Переменные Эрланга не меняются, поэтому мы должны быть креативными.К счастью, у нас есть опции ...

Мы можем передать переменную Counter с нашими функциями и увеличивать ее при каждом вызове функции.Мы можем использовать словарь процессов для хранения счетчика, а get и put для его увеличения.Мы можем использовать ETS, локальное хранилище данных для процессов.Мы можем использовать встречный процесс (!!!):

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.

Я уверен, что есть и другие способы, в зависимости от области применения.Что считается «лучшей практикой» для приращения переменной в Erlang?

Ответы [ 4 ]

9 голосов
/ 29 сентября 2010

Не используйте словарь процессов.

Ожидаемый «нормальный» цикл (т. Е. Цикл for или do while) обычно реализуется в рекурсивной функции в Erlang, поэтому еслиВы увеличиваете «нормальный» счетчик, делайте это в вызовах функций, как если бы вы отображались вверху.

Не используйте словарь процессов.

Если вы пропустили, могу я просто указатьчто вы не должны использовать словарь процесса.

3 голосов
/ 30 августа 2012

Я думаю, что вы создали из этого большое дело, в то время как вы можете справиться с этим гораздо проще.
Рассмотрим эту реализацию цикла for в Erlang:

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

Хотя F - это функция, которую вы хотите сохранить, ее результаты для значений от I до Max.
Разве это не легче понять?

3 голосов
/ 29 сентября 2010

Все зависит от того, для чего вы используете счетчик. Все глобальное, например, количество сообщений, обрабатываемых системой q, должно использовать ets: update_counter. Если он не глобальный, я обычно просто включаю его в параметры, которые вы показали.

0 голосов
/ 05 октября 2010

Стандартный способ увеличения счетчика такой же, как в первом примере. Добавляя переменную к вызову и увеличивая ее. Я думаю, что вас смущает отсутствие циклов for и возможность обновления значений.

Обратите внимание, что:

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

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

компилируется (более или менее) так же, как (в псевдокоде):

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

Если вы хотите накапливать результат, есть и способы сделать это.

Либо используйте пакет списков, либо накапливайте результат самостоятельно:

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.

Или что-то похожее на основе вашего примера.

Редактировать: возвращаемое значение Count также является частью возвращаемого значения, поскольку оно представляется важным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...