4

私はゲーム理論の学習を研究するために図書館で働いています。この設定では、Nエージェントがまとめられ、環境と対話します。各エージェントは、相互作用のモデルを導き出します。1つのエージェントのモデルは、そのN-1対戦相手によって異なります。1エージェントとエージェントのモデルを決定するコードを作成し2、それを一般化しようとしています。これが私が持っているコードの一部です:

data System w x a s h h' = System { signaling :: SignalingWXAS w x a s
                                  , dynamic   :: DynamicXAS x a s
                                  , strategy  :: MockupStrategy x a s h h' }

data JointState w x a s h h' = JointState { worldState  :: w
                                          , state       :: x
                                          , mockupState :: MockupState a s h h' }

systemToMockup :: ( Bounded w, Ix w, Bounded x, Ix x
                  , Bounded a, Ix a, Bounded s, Ix s
                  , Bounded (h a), Ix (h a), Bounded (h' s), Ix (h' s)
                  , History h, History h'
                  ) => System w x a s h h' -> Mockup a s h h'
systemToMockup syst = mock
    where
      mock z   = norm $ statDist >>=? condit z >>= computeStatesAndAction >>= sig >>=$ extractSignal
      statDist = ergodicStationary $ transition syst
      condit z = just z . mockupState
      sig      = uncurryN $ signaling syst
      strat    = strategy syst
      computeStatesAndAction joint = do
        let w = worldState joint
        let x = state joint
        a <- strat x (mockupState joint)
        return (w, x, a)
      extractSignal (_, s) = s

data System2 w x1 a1 s1 h1 h1' x2 a2 s2 h2 h2' = System2 { signaling :: SignalingWXAS2 w x1 a1 s1 x2 a2 s2
                                                         , dynamic1  :: DynamicXAS x1 a1 s1
                                                         , dynamic2  :: DynamicXAS x2 a2 s2
                                                         , strategy1 :: MockupStrategy x1 a1 s1 h1 h1'
                                                         , strategy2 :: MockupStrategy x2 a2 s2 h2 h2' }

data JointState2 w x1 a1 s1 h1 h1' x2 a2 s2 h2 h2' = JointState2 { worldState   :: w
                                                                 , state1       :: x1
                                                                 , mockupState1 :: MockupState a1 s1 h1 h1'
                                                                 , state2       :: x2
                                                                 , mockupState2 :: MockupState a2 s2 h2 h2' }
systemToMockups2 syst = (mock1, mock2)
    where
      mock1 z1   = norm $ statDist >>=? condit1 z1 >>= computeStatesAndActions >>= sig >>=$ extractSignal1
      mock2 z2   = norm $ statDist >>=? condit2 z2 >>= computeStatesAndActions >>= sig >>=$ extractSignal2
      statDist   = ergodicStationary $ transition2 syst
      condit1 z1 = just z1 . mockupState1
      condit2 z2 = just z2 . mockupState2
      sig        = uncurryN $ signaling syst
      strat1     = strategy1 syst
      strat2     = strategy2 syst
      computeStatesAndActions joint = do
        let w  = worldState joint
        let x1 = state1 joint
        let x2 = state2 joint
        a1 <- strat1 x1 (mockupState1 joint)
        a2 <- strat2 x2 (mockupState2 joint)
        return (w, x1, a1, x2, a2)
      extractSignal1 (_, s, _) = s
      extractSignal2 (_, _, s) = s

私は、systemToMockupN有限数のエージェントに対応できる関数定義を求めています。

エージェントは異種であるため、リストを直接使用することはできません。事前にサイズがわからないのでタプルは使えません。curryN、などを使用してみuncurryNましたが、タプルのすべての要素に対して1つの操作を実行できませんでした。同様の方法で可変個引数関数を作成しようとしましたprintfが、成功しませんでした。

テンプレートhaskellを使用できることは知っていますが、見落としているより良い解決策があるかどうか疑問に思っています。有限であるが任意の数の異種要素を処理するコードへのポインタは大歓迎です。

4

5 に答える 5

3

異質にならないでください。それはそれだけの価値はありません。より良い方法を見つけること価値があります。これを回避するための1つのアプローチがあります。(他のパスもあります。)エージェントの数は任意ですが、エージェントの種類は任意ではありません。(タイプは本当にパラメータ化する必要がありますか?あなたの一般性は私が恐れているあなたにあまりにも多くの費用をかけています。

    class AnAgent a where 
         liveABit :: World -> a -> (World,a)
         ...
         ...

    data NuclearPlant = ....
    data CoalPlant = ....
    data WidFarm = .....

    data DataCenter = .....

    data EnvFriendly = .....
    data PetrolHead = .....

便利な場合は、パターンマッチングを介して一般的な処理を行うために、それらを少しグループ化します。

    data Plant = PN NuclearPlant | PC CoalPlant | PW WindFarm
    data Human = HEF EnvFriendly | HPE PetrolHead

    data Agent = AP Plant | AH Human | AD DataCenter

グループ内/グループ間での一般的/不均一な治療:

    bump :: Agent -> Agent
    bump (Human h) = Human (breakleg h)
    bump a = a

次に、必要なすべてのエージェントを定義してから、それらをにポップして、ワールドとそのエージェントを更新[Agent]するための適切なものを定義できます。個々のエージェントタイプまたはグループのインスタンスを作成し、まで構築するeachLiveABit :: World -> [Agent] -> (World,[Agent])ことができます(または、タイプクラスがなくても、通常の関数を使用することもできます)。AnAgentAgent

(Classes + Interesting Type System Features) -> (Types and Higher Order Functions)これは、少し落ち込んでいるように感情的に感じるプログラム変換に従いますが、問題の多くは解決します。

于 2012-09-20T17:13:29.073 に答える
3

異種。私はあなたがこれをするべきではないと思います、しかしあなたは尋ねました。

HListなどの異種リストには既存のライブラリを使用できます。これはとにかくテンプレートHaskellを密かに使用しますが、自分でやったように手を汚す必要はありません。

動的型付けを使用する言語には、キャストなどの必要性のためにあらゆる種類の問題があります。HListは型に対して安全ですが、うまく機能し、バグのないコードを書くことは私の見解ではまだ簡単ではありません。タイプを変更する必要がないため、タプルよりも優位に立つことができます。また、要素間での更新のマッピングは簡単になるはずですが、それでもきれいではありません。

于 2012-09-20T17:19:06.200 に答える
2

一般化代数的データ型(GADT)。

これらを使用すると、非常に多くの真に異種のデータ型を1つにまとめることができ、実存的な型を実行するための最新の方法です。data Agent = AH Human | AP Plant | ....彼らはアプローチとアプローチの間のどこかに座っていHListます。あるタイプクラスの信じられないほど異種のエージェントインスタンスをすべて作成し、それらをにまとめることができますAgentGADT。明示的な型を持つ関数がないとGADTからデータを取り戻すのは難しいため、型クラスにエージェントに対して実行したいことがすべて含まれていることを確認してください。必要getHumans [AgentGADT] -> [Human]ですか?またはupdateHumans :: (Human->Human) -> [AgentGADT] -> [AgentGADT]?これは、他の投稿の通常の抽象データ型を使用した方が簡単です。

プラスポイント:[AgentGADT]奇妙で素晴らしくパラメータ化されたデータ型を記述しながら、クラス関数を使用して均一に操作できます。マイナスポイント-一度入ったらエージェントデータを取り出すのは難しい。

オンラインでの私のお気に入りの紹介テキストは、ダミー用のGADTでした

于 2012-09-20T17:28:44.713 に答える
0

型クラスを使用してそれを解決しようとすることができます。
ここにいくつかの擬似コードがあります:

data Mockup = Mockup1 <return type of systemToMockup>
            | Mockup2 <return type of systemToMockups2>

class SystemToMockup a where
    systemToMockup :: a -> Mockup

instance SystemToMockup (System1 ...) where
    <implementation of systemToMockup>

instance SystemToMockup (System2 ...) where
    <implementation of systemToMockups2>

これはかなり限定された解決策であり、アプリケーションが非常に複雑であるように思われるため、うまくいくとは思えません。
一般的に、CAMcCannのアプローチははるかに優れています。

于 2012-09-20T15:21:45.610 に答える
0

更新:この戦略で処理できないことの1つは、ポリモーフィックリターンタイプです。また、メインタイプに応じてタイプが異なるパラメータは、かなり複雑になります。

コメントで言及されていますが、「異種コレクション」を実行するための最良の方法の1つは、コレクションの各要素に対して実際に実行できる操作を決定することです(制限された一連の操作しか実行できないため)それらに、たとえあなたの言語がダックタイピングを持っていたとしても)そしてそれらの操作の記録を保存してください。例:

data Thing1 = ...
data Thing2 = ...

data AThing = AThing {
  op1 :: ...
  op2 :: ...
}

class IsAThing a where
    mkAThing :: a -> AThing

instance IsAThing Thing1 where
    mkAThing a = AThing {
            op1 = op1_for_thing1 a,
            op2 = op2_for_thig1 a
        }

次に、op1IsAThingを呼び出すには:

op1 (mkAThing a) <...other args...>

ただし、あなたの場合は、次のリストが必要ですAThing

[mkAThing a2, mkAThing a2, ...]

次に、任意の要素で:

op1 <element of that list> <...other args...>
于 2012-09-20T20:27:30.913 に答える