2008-09-15 8 views
3

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

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

私の問題はもちろん記録です...私はそれらを動的に作成したり、2つを一緒に、または何かをマージする方法は見つけられません。好ましくは、私は次のように呼び出すことができる関数があります。

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

答えて

2

私は2つのレコードをマージし、そのしばらく前にいくつかのコードを書いて、完全にダイナミックではありませんが、マクロwhithあなたは簡単に複数のレコードのためにそれを使用することができます

それは次のように動作します。。マージ/ 2機能がかかります2つのレコードを参照のために空のレコードとともにリストに変換します(レコードタイプはコンパイル時に定義されていますが、これは "動的ではない"部分です)。リストがあり、定義されている場合はAから、そうでなければ定義されている場合はBから、最後には常に定義されているデフォルトから(最後には常に定義されています)。構文の強調表示):

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

気軽に自由に使用できます。

3

レコードの汎用アクセス関数を書くのは難しいです。 この問題の回避策の1つは'exprecs'ライブラリで、 は低レベルのレコードアクセス機能用のコードを生成します。

あなたがする必要がある事は モジュールに次の行を追加することです:

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

アクセス関数の命名規則は奇妙に見えるかもしれませんが、リチャード・オキーフからの提案に触発されました。少なくとも、一貫性があり、既存の機能と衝突する可能性はほとんどありません。 (:

+0

これは私が探していたものではないかもしれません。それにもかかわらず、面白いと私は後でチェックします。 –

関連する問題