3

コール キュー内のエージェントの現在のステータスを収集するソフトウェア用のコードをリファクタリングしようとしています。現在、リッスンする 6 つほどのイベントのそれぞれについて、エージェントが存在するかどうかを Mnesia テーブルにチェックインし、イベントに応じて行の値を変更するか、エージェントが存在しない場合は新しいものとして追加します。現在、私は各イベントでこの Mnesia トランザクションを持っています。もちろん、エージェントの存在などをチェックするための一連のコードが繰り返されています。

これを変更して、これを処理するイベントから呼び出すchange_agent/2のような関数が 1 つあるようにしようとしています。

もちろん、私の問題はレコードです....それらを動的に作成したり、2つをマージしたりする方法が見つかりません。できれば、次のように呼び出すことができる関数があるでしょう。

change_agent("001", #agent(id = "001", name = "Steve")).
change_agent("001", #agent(id = "001", paused = 0, talking_to = "None")).
4

2 に答える 2

3

レコードに対する一般的なアクセス関数を記述するのは困難です。これに対する 1 つの回避策は、低レベルのレコード アクセス関数のコードを生成する'exprecs'ライブラリです。

必要なことは、次の行をモジュールに追加することです。

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

アクセス関数の命名規則は奇妙に見えるかもしれませんが、Richard O'Keefe からの提案に触発されました。少なくとも一貫性があり、既存の関数と衝突する可能性は低いです。(:

于 2008-09-15T12:55:56.700 に答える
2

少し前に、2 つのレコードをマージするコードを書きました。完全に動的ではありませんが、マクロを使用すると、複数のレコードに簡単に使用できます.

次のように動作します: merge/2 関数は 2 つのレコードを取り、それらを参照用の空のレコードと一緒にリストに変換します (レコードの型はコンパイル時に定義され、そうでなければなりません。これは「非動的」部分です)。これらは、リストで動作し、定義されている場合は A から要素を取得し、定義されている場合は B から要素を取得し、最後に Default (常に定義されている) から要素を取得するジェネリック関数 merge/4 を介して実行されます。

コードは次のとおりです (StackOverflow の貧弱な Erlang 構文の強調表示を許してください):

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

お好きな方法でご自由にお使いください。

于 2008-09-15T13:32:15.083 に答える