【问题标题】:Haskell: "how much" of a type should functions receive? and avoiding complete "reconstruction"Haskell:函数应该接收“多少”类型?避免彻底的“重构”
【发布时间】:2012-06-13 15:12:31
【问题描述】:

我有这些数据类型:

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)

我只是使用BodyPointPlus 部分,而不是整个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,则必须有另一个函数在新的Body 中调用它。我解释一下:有一个函数update 被调用来更新游戏状态;它传递当前的游戏状态,现在是单个Body,并返回更新后的Body

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

这让我发痒。除了PointPlusBody 中的所有内容都保持不变。有没有办法手动避免这种完全的“重建”?喜欢在:

update body = backInBody $ move $ pointPlus body

当然不必定义backInBody

【问题讨论】:

    标签: function haskell types


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 太完美了,尤其是自动生成! move 函数呢?是把整个Body 拿走还是只拿它的PointPlus 一部分更好?
    • @L01man 我还在我关于镜头的博客文章中描述了一个与您非常相似的具体示例here
    • 您的分步说明帮助我全面了解镜头。
    • 你不认为 Haskell 应该默认实现镜头吗?类型是语言的一部分,记录语法对于镜头来说有点多余,但功能较弱。
    猜你喜欢
    • 1970-01-01
    • 2013-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    相关资源
    最近更新 更多