4

我正在研究博弈论学习的图书馆。在这种情况下,N代理聚集在一起并与环境交互。每个代理派生一个交互模型。一个代理的模型取决于它的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等,但没有设法对元组的每个元素进行一次操作。我尝试以类似于printf没有成功的方式构建可变参数函数。

我知道我可以使用模板 haskell,但我想知道是否有更好的解决方案我忽略了。任何指向处理有限但任意数量的异构元素的代码的指针将不胜感激。

4

5 回答 5

3

异质的。我认为你不应该这样做,但你确实问过了。

您可以将现有的库用于异构列表,例如HList。无论如何,这秘密地使用了 Template Haskell,但你不需要像你自己做的那样弄脏你的手。

由于需要强制转换等,具有动态类型的语言存在各种问题。 HList 是类型安全的,但在我看来,编写运行良好且没有错误的代码仍然不容易。你比元组更有优势,因为你不需要改变类型,跨元素映射你的更新应该更容易,但它仍然不漂亮。

于 2012-09-20T17:19:06.200 回答
3

不要异类。这不值得。值得寻找更好的方法这是避免它的一种方法。(还有其他路径。)可能有任意数量的代理,但肯定不存在任意数量的代理类型。(类型真的需要如此参数化吗?我担心你的概括性会让你付出太多代价。

    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]并定义一个 niceeachLiveABit :: World -> [Agent] -> (World,[Agent])来更新世界及其代理。您可以创建AnAgent单个代理类型或组的实例,并构建到Agent, (或者甚至可以不使用类型类,只使用普通函数)。

这将遵循(Classes + Interesting Type System Features) -> (Types and Higher Order Functions)程序转换,在情感上感觉就像你有点笨拙,但会消除很多麻烦。

于 2012-09-20T17:13:29.073 回答
2

广义代数数据类型 (GADT)。

这些使您可以将有限的许多真正异构的数据类型合并为一个,并且是处理存在类型的现代方法。data Agent = AH Human | AP Plant | ....他们坐在进场和进场之间的某个地方HList。您可以将所有令人难以置信的异构代理实例化为某个类型类,然后将它们捆绑在AgentGADT. 确保你的 typeclass 包含你想要对 Agent 做的所有事情,因为如果没有具有显式类型的函数,很难从 GADT 中取回数据;你需要getHumans [AgentGADT] -> [Human]吗?还是updateHumans :: (Human->Human) -> [AgentGADT] -> [AgentGADT]?使用我另一篇文章中的普通抽象数据类型会更容易。

加分项:您可以[AgentGADT]使用类函数统一使用和操作,同时编写奇怪且奇妙的参数化数据类型。减分 - 一旦您的代理数据进入,就很难将其取出。

我最喜欢的在线介绍性文字是GADTs for dummy

于 2012-09-20T17:28:44.713 回答
0

更新:该策略无法处理的一件事是多态返回类型。此外,根据主要类型具有不同类型的参数会增加相当多的复杂性。

评论中已经提到过,但是进行“异构集合”的最佳方法之一是确定您可以对集合的每个元素实际执行哪些操作(因为您只能执行一组受限的操作在它们上,即使您的语言有鸭式打字)并存储这些操作的记录。例子:

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
        }

然后,调用op1任何 IsAThing:

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

但是,在您的情况下,您需要以下列表AThing

[mkAThing a2, mkAThing a2, ...]

然后在任何元素上:

op1 <element of that list> <...other args...>
于 2012-09-20T20:27:30.913 回答
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>

这是一个相当有限的解决方案,我怀疑它是否适合您,因为您的应用程序似乎相当复杂。
一般来说,CA McCann 的方法要好得多。

于 2012-09-20T15:21:45.610 回答