首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >处理有限但任意数量的异质元素的函数

处理有限但任意数量的异质元素的函数
EN

Stack Overflow用户
提问于 2012-09-20 22:18:07
回答 5查看 216关注 0票数 4

我在一个图书馆工作,研究博弈论学习。在此设置中,N代理集中在一起并与环境交互。每个智能体都派生出一个交互模型。一个智能体的模型取决于它的N-1对手。我为1代理和2代理编写了确定该模型的代码,并试图对其进行泛化。下面是我的部分代码:

代码语言:javascript
复制
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

代码语言:javascript
复制
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的函数定义,它可以容纳任何有限数量的代理。

代理是异构的,因此不能直接使用列表。我不能使用元组,因为我事先不知道大小。我尝试使用curryNuncurryN等,但无法在元组的每个元素上执行一次操作。我尝试用类似于printf的方式构建一个可变函数,但没有成功。

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

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-09-21 01:28:45

通用代数数据类型(GADT)。

这让你可以将有限多个真正的异构数据类型放在一起,并且是实现存在类型的现代方法。它们介于data Agent = AH Human | AP Plant | ....方法和HList方法之间。您可以创建某些类型类的所有非常异构的代理实例,然后在AgentGADT中将它们捆绑在一起。确保您的类型类包含了您想要对其中的代理执行的所有操作,因为如果没有显式类型的函数,就很难从GADT中获取数据;您需要getHumans [AgentGADT] -> [Human]吗?或者是updateHumans :: (Human->Human) -> [AgentGADT] -> [AgentGADT]?在我的另一篇文章中,使用普通的抽象数据类型会更容易。

优点:您可以使用[AgentGADT],并使用类函数统一操作,同时编写奇怪而奇妙的参数化数据类型。减分-一旦进入,你的代理数据就很难拿出来。

我最喜欢的在线介绍文本是GADTs for dummies

票数 2
EN

Stack Overflow用户

发布于 2012-09-21 01:13:29

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

代码语言:javascript
复制
    class AnAgent a where 
         liveABit :: World -> a -> (World,a)
         ...
         ...

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

    data DataCenter = .....

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

如果方便的话,可以通过模式匹配将它们组合在一起进行通用处理:

代码语言:javascript
复制
    data Plant = PN NuclearPlant | PC CoalPlant | PW WindFarm
    data Human = HEF EnvFriendly | HPE PetrolHead

    data Agent = AP Plant | AH Human | AD DataCenter

组内的共同/异质治疗/交叉组:

代码语言:javascript
复制
    bump :: Agent -> Agent
    bump (Human h) = Human (breakleg h)
    bump a = a

然后,您可以定义所有想要的代理,然后将它们弹出到[Agent]中,并定义一个很好的eachLiveABit :: World -> [Agent] -> (World,[Agent])来更新世界及其代理。您可以创建单个代理类型或组的AnAgent实例,并构建为Agent (或者甚至可以不使用类型类,只使用普通函数)。

这将遵循(Classes + Interesting Type System Features) -> (Types and Higher Order Functions)程序转换,它在情感上感觉有点像您的笨蛋,但却消除了大部分麻烦。

票数 3
EN

Stack Overflow用户

发布于 2012-09-21 01:19:06

异质的。我觉得你不应该这么做,但你确实问过了。

你可以使用一个现有的库来处理异类列表,比如HList。这暗地里使用了模板Haskell,但你不需要亲手动手,就像你自己做一样。

具有动态类型的语言有各种各样的问题,因为需要强制转换等。HList是类型安全的,但在我看来,编写工作良好且没有but的代码仍然不容易。您比元组更有优势,因为您不需要更改类型,并且跨元素映射您的更新应该更容易,但它仍然不是很好。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12514619

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档