设计代表Haskell中“物种”的类型类

时间:2012-07-24 19:40:27

标签: haskell typeclass

以下简化数据类型是游戏所有对象的基础:

data Object = Object { logic :: Logic, picture :: Picture }
data Logic = Logic { geometry :: Geometry, someAttributes :: SomeAttributes }
data Geometry = Geometry { coords :: Point, size :: Point }
data SomeAttributes = SomeAttributes { life :: Int, hasGravity :: Bool }

对象由函数创建:

hero position = Object
    (Logic
        (Geometry position (Point 25 55))
        (SomeAttributes 100 True))
    PictureConstructor1

enemy position = Object
    (Logic
        (Geometry position (Point 25 25))
        (SomeAttributes 3 True))
    PictureConstructor2

bullet position = Object
    (Logic
        (Geometry position (Point 5 5))
        (SomeAttributes 0 False))
    PictureConstructor3

--etc. for blocks and everything else

游戏结构示例:

[hero (Point 0 0), enemy (Point 50 0), enemy (Point 100 0), block (Point 0 (negate 30)), block (Point 50 (negate 30)), block (Point 100 (negate 30))]

然后,advance函数获取此列表并应用重力,碰撞......,从而使对象移动,死亡,...... 此函数的类型为[Object] -> [Object],但不会更改Object的所有字段:仅更改coordslife,而size和{例如,{1}}始终保持不变,不受影响。

这个常量数据代表某种“特殊属性”或类属性,但“实例”会携带它们,这是不安全重内存 不实用用于序列化。


我想过创建一个类型类,每个实例都会提供它们的“常量”和一个可以改变的字段的构造函数。我想不出更好的东西:

hasGravity

它更轻,更安全,但它相当难看,因为它失去了它的结构(不再是逻辑,几何,......)。我想如果它们存在,我会使用lambda类型:p。

请分享您对如何解决这些问题或您可以考虑的替代模型的想法。

1 个答案:

答案 0 :(得分:1)

  

问题在于所有这些物种特定的领域都可以通过其他功能进行修改,但在比赛中唯一可以改变的是比赛位置和生命点。

由于haskell中的所有数据结构都是不可变的,我假设当你说修改时,你的意思是其他函数可以使用数据构造函数构造新的(可能是不同的)对象。

如果要防止这种情况发生,可以将数据类型与构造它们的函数(heroenemybullet)放在一个仅导出的额外模块中数据类型的类型构造函数以及访问字段和构造函数的函数,但不包括数据构造函数。

module GameData (Object, Logic, Geometry, SomeAttributes, logic, picture, geometry, someAttributes, coords, size, life, hasGravity, hero, enemy, bullet)

data Object = CreateObject { logic :: Logic, picture :: Picture }
data Logic = CreateLogic { geometry :: Geometry, someAttributes :: SomeAttributes }
data Geometry = CreateGeometry { coords :: Point, size :: Point }
data SomeAttributes = CreateSomeAttributes { life :: Int, hasGravity :: Bool }

hero position = ...
enemy position = ...
bullet position = ...

然后您可以选择要公开的数据构造函数。将所有'可变'数据放入其自己的数据类型中可能是有意义的,因此您可以导出该数据类型的数据构造函数,但不能导出其他数据类型的数据构造函数。

一旦你有了这样的组织,你就可以非常严格地控制你的对象的构造方式,因为那些模块是唯一可以构建这个构造的模块,其他模块只能访问hero enemybullet函数。