Вопрос

Я пытаюсь реорганизовать некоторый имеющийся у меня код для программного обеспечения, которое собирает текущее состояние агентов в очереди вызовов.В настоящее время для каждого из 6 или около того событий, которые я прослушиваю, я проверяю в таблице Mnesia, существует ли агент, и изменяю некоторые значения в строке в зависимости от события или добавляю его как новое, если агент не существует.В настоящее время у меня есть эта транзакция Mnesia в каждом событии, и, конечно, это куча повторяющегося кода для проверки существования агентов и так далее.

Я пытаюсь изменить это так, чтобы была одна функция, например change_agent/2 изменить агент/2 который я вызываю из events, который обрабатывает это за меня.

Мои проблемы - это, конечно, записи....Я не нахожу способа динамически создавать их или объединять 2 из них вместе или что-то в этом роде.Предпочтительно, чтобы существовала функция, которую я мог бы вызвать следующим образом:

change_agent("001", #agent(id = "001", name = "Steve")).
change_agent("001", #agent(id = "001", paused = 0, talking_to = "None")).
Это было полезно?

Решение

Некоторое время назад я написал некоторый код, который объединяет две записи.Он не совсем динамичен, но с помощью макросов вы могли бы легко использовать его для нескольких записей.

Это работает следующим образом:Функция merge/2 принимает две записи и преобразует их в списки вместе с пустой записью для ссылки (тип записи определяется во время компиляции и должен быть.Это "нединамичная" часть).Затем они запускаются через универсальную функцию merge / 4, которая работает со списками и принимает элементы из A, если они определены, в противном случае из B, если они определены, или, наконец, из Default (который всегда определяется).

Вот код (пожалуйста, извините за плохую подсветку синтаксиса Erlang в StackOverflow):

%%%----------------------------------------------------------------------------
%%% @spec merge(RecordA, RecordB) -> #my_record{}
%%%     RecordA = #my_record{}
%%%     RecordB = #my_record{}
%%%
%%% @doc Merges two #my_record{} instances. The first takes precedence.
%%% @end
%%%----------------------------------------------------------------------------
merge(RecordA, RecordB) when is_record(RecordA, my_record),
                             is_record(RecordB, my_record) ->
    list_to_tuple(
        lists:append([my_record],
                     merge(tl(tuple_to_list(RecordA)),
                           tl(tuple_to_list(RecordB)),
                           tl(tuple_to_list(#my_record{})),
                           []))).

%%%----------------------------------------------------------------------------
%%% @spec merge(A, B, Default, []) -> [term()]
%%%     A = [term()]
%%%     B = [term()]
%%%     Default = [term()]
%%%
%%% @doc Merges the lists `A' and `B' into to a new list taking
%%% default values from `Default'.
%%%
%%% Each element of `A' and `B' are compared against the elements in
%%% `Default'. If they match the default, the default is used. If one
%%% of them differs from the other and the default value, that element is
%%% chosen. If both differs, the element from `A' is chosen.
%%% @end
%%%----------------------------------------------------------------------------
merge([D|ATail], [D|BTail], [D|DTail], To) ->
    merge(ATail, BTail, DTail, [D|To]); % If default, take from D
merge([D|ATail], [B|BTail], [D|DTail], To) ->
    merge(ATail, BTail, DTail, [B|To]); % If only A default, take from B
merge([A|ATail], [_|BTail], [_|DTail], To) ->
    merge(ATail, BTail, DTail, [A|To]); % Otherwise take from A
merge([],        [],        [],        To) ->
    lists:reverse(To).

Не стесняйтесь использовать его так, как вам захочется.

Другие советы

Сложно написать общие функции доступа к записям.Одним из обходных путей для этого является "экспреки" библиотека, которая будет генерировать код для низкоуровневых функций доступа к записям.

Все, что вам нужно сделать, это добавить следующие строки в модуль:

-compile({parse_transform, exprecs}).
-export_records([...]).  % name the records that you want to 'export'

Соглашение об именовании функций доступа может показаться странным, но оно было вдохновлено предложением Ричарда О'Кифа.Он, по крайней мере, последователен и вряд ли будет вступать в противоречие с существующими функциями.(:

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top