10

我有这些数据类型:

data PointPlus = PointPlus
    { coords :: Point
    , velocity :: Vector
    } deriving (Eq)

data BodyGeo = BodyGeo
    { pointPlus :: PointPlus
    , size :: Point
    } deriving (Eq)

data Body = Body
    { geo :: BodyGeo
    , pict :: Color
    } deriving (Eq)

它是我游戏中角色、敌人、物体等的基本数据类型(好吧,我现在只有两个矩形作为玩家和地面:p)。

当一个键时,字符向右、向左移动或通过改变它的velocity. 移动是通过添加 到velocity来完成的coords。目前,它的编写如下:

move (PointPlus (x, y) (xi, yi)) = PointPlus (x + xi, y + yi) (xi, yi)

我只是参加PointPlusmy 的一部分Body而不是整个Body,否则它将是:

move (Body (BodyGeo (PointPlus (x, y) (xi, yi)) wh) col) = (Body (BodyGeo (PointPlus (x + xi, y + yi) (xi, yi)) wh) col)

第一个版本move更好吗?无论如何,如果move只是更改PointPlus,则必须有另一个函数在 new 中调用它Body。我解释一下:有一个函数update被调用来更新游戏状态;它传递当前的游戏状态,Body现在是一个,并返回更新的Body.

update (Body (BodyGeo (PointPlus xy (xi, yi)) wh) pict) = (Body (BodyGeo (move (PointPlus xy (xi, yi))) wh) pict)

这让我很痒。里面的一切都保持不变,Body除了PointPlus. 有没有办法手动避免这种完全的“重建”?像:

update body = backInBody $ move $ pointPlus body

当然,不必定义backInBody

4

1 回答 1

14

您正在寻找“镜头”。镜头有几种不同的包装;是对它们的一个很好的总结。

a我的理解是,某个字段的数据类型的镜头b提供了两种操作:一种获取 的值的方法,b以及一种获取a具有不同值的新的b. 因此,您只需使用镜头来处理深度嵌套的PointPlus.

镜头包提供了使用镜头的有用功能以及自动生成镜头的方法(使用模板 Haskell),这非常方便。

我认为它们值得为您的项目研究,特别是因为由于数据类型的结构,您可能会在其他地方遇到类似的嵌套问题。

于 2012-06-10T10:24:02.387 回答