简体   繁体   English

Haskell:函数应该接收“多少”类型?并避免完全“重建”

[英]Haskell: “how much” of a type should functions receive? and avoiding complete “reconstruction”

I've got these data types: 我有这些数据类型:

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)

It's the base datatype for characters, enemies, objects, etc. in my game (well, I just have two rectangles as the player and the ground right now :p). 它是我游戏中角色,敌人,物体等的基本数据类型(好吧,我现在只有两个矩形作为玩家和地面:p)。

When a key, the characters moves right, left or jumps by changing its velocity . 当一个键时,字符通过改变其velocity向右,向左或跳跃。 Moving is done by adding the velocity to the coords . 通过将velocity添加到coords来完成移动。 Currently, it's written as follows: 目前,它的编写如下:

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

I'm just taking the PointPlus part of my Body and not the entire Body , otherwise it would be: 我只是把PointPlus作为我Body一部分,而不是整个Body ,否则它将是:

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

Is the first version of move better? move的第一个版本更好吗? Anyway, if move only changes PointPlus , there must be another function that calls it inside a new Body . 无论如何,如果move只改变了PointPlus ,那么必须有另一个函数在一个新的Body中调用它。 I explain: there's a function update which is called to update the game state; 我解释一下:有一个函数update被调用来更新游戏状态; it is passed the current game state, a single Body for now, and returns the updated Body . 它传递给当前游戏状态,现在是一个Body ,并返回更新的Body

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

That tickles me. 这让我感到痒痒。 Everything is kept the same within Body except the PointPlus . PointPlus外, Body内的所有内容都保持不变。 Is there a way to avoid this complete "reconstruction" by hand? 有没有办法避免手工完成“重建”? Like in: 像:

update body = backInBody $ move $ pointPlus body

Without having to define backInBody , of course. 当然,无需定义backInBody

You're looking for "lenses". 你正在寻找“镜头”。 There are several different packages for lenses; 镜片有几种不同的包装; here is a good summary of them. 是对它们的一个很好的总结。

My understanding is that a lens on a data type a for some field b provides two operations: a way to get the value of b and a way to get a new a with a different value of b . 我的理解是,在一个数据类型的镜头a对一些领域b提供了两个操作:一种方式来获得的值b和一种方式来获得一个新的a具有不同的值b So you would just use a lens to work with the deeply nested PointPlus . 因此,您只需使用镜头即可使用深度嵌套的PointPlus

The lens packages provide useful functions for working with lenses as well as ways of generating lenses automatically (with template Haskell) which could be very convenient. 镜头包提供了与镜头一起使用的有用功能以及自动生成镜头的方法(使用模板Haskell),这可能非常方便。

I think they are worth looking into for your project, especially because you are likely to encounter similar problems with nesting in other places thanks to the structure of your data types. 我认为他们值得研究您的项目,特别是因为您的数据类型结构可能会遇到类似的嵌套问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM