类型检查器可以帮助我吗? 有类型的家庭,也许?

所以我现在正在写这个小小的足球比赛,有一件事从一开始就让我感到困惑。 游戏遵循Yampa Arcade模式,所以游戏中的“对象”有一个总和类型:

data ObjState = Ball Id Pos Velo
              | Player Id Team Number Pos Velo
              | Game Id Score

对象对消息作出反应,所以还有另一种总和类型:

data Msg = BallMsg BM
         | PlayerMsg PM
         | GameMsg GM
data BM = Gained | Lost
data PM = GoTo Position | Shoot
data GM = GoalScored | BallOutOfBounds

Yampa框架依赖于所谓的信号功能。 在我们的例子中,有球,球员和游戏行为的信号功能。 粗略简化:

ballObj, playerObj, gameObj :: (Time -> (GameInput, [Msg])) 
                               -> (Time -> (ObjState, [(Id, Msg)]))

因此,例如ballObj需要一个函数,该函数可以在任何给定时间产生GameInput(击键,游戏状态......)以及专门用于球的消息列表,并返回一个函数,该函数可以产生球的状态,并将消息传递给其他对象(球,游戏,球员)在任何给定的时间。 在Yampa,类型签名实际上看起来更好一些:

ballObj, playerObj, gameObj :: SF (GameInput, [Msg]) (ObjState, [(Id, Msg)])

这种统一类型的签名对于Yampa框架是非常重要的:(再次,非常粗暴地简化了),它从11 + 11(玩家)+ 1(球)+ 1(游戏)信号函数列表中建立了一个大信号函数, (通过dpSwitch),然后运行(通过reactimate)。

所以,现在,什么使我感到困惑:将BallMsg发送给球或者将PlayerMsg发送给玩家才有意义。 如果有人将例如GameMsg发送给Ball,程序将会崩溃。 没有办法让类型检查器避免这种情况吗? 我最近在类型系列中阅读了这个不错的Pokemon帖子,似乎有些类比。 所以也许这可能是一个起点:

class Receiver a where
  Msg a :: *
  putAddress :: Msg a -> a -> Msg a

data BallObj = ...
data GameObj = ...
data PlayerObj = ...

instance Receiver BallObj where
  Msg BallObj = Gained | Lost
(...)

现在,SF功能可能如下所示:

forall b . (Receiver a, Receiver b) => SF (GameInput, [Msg a]) (a, [(b, Msg b)])

这会让我到哪里?


从乍一看直观你的设计的一个主要问题突出:你在单一类型下统一了完全不同的实体BallPlayerGame 。 如果你需要这些实体的联合类型,那么通过使它们成为不同的类型来使用与消息相同的方式,即:

data AnyObject = AnyObjectBall Ball
               | AnyObjectPlayer Player
               | AnyObjectGame Game

这样你就可以表达具体的功能( Ball -> BallMsg -> ... )和一般的功能( AnyObject -> AnyMsg -> ... )。

但如果我正确理解你的问题,我想我有一个解决方案,你不需要联盟类型:

class Signal object message where
  signal :: SF (GameInput, [message]) (object, [(Id, message)])

data Ball = Ball Id Pos Velo
data BallMsg = BallMsgGained | BallMsgLost
instance Signal Ball BallMsg where
  -- ...

-- so on for Player and Game

浏览yampa街机纸,似乎你有一个从他们的例子中绘制的route功能。

我的建议是你改变route所以它不需要一个单一的对象列表,而是一个单一的游戏对象,一个单一的球对象和一系列球员对象。 然后有

data BallMsg = ...
data PlayerMsg = ...
data GameMsg = ...

data AnyMsg = ABallMsg BallMsg
            | APlayerMsg PlayerMsg
            | AGameMsg GameMsg

现在route工作在一个统一的AnyMsg但是根据它们的内容将它们分派到正确的目的地。

链接地址: http://www.djcxy.com/p/13709.html

上一篇: Can the type checker help me out here? With type families, maybe?

下一篇: Loading Adobe Illustrator(.ai) file