gpt4 book ai didi

purescript - 适当的抽象代替异构(但共享类)列表?

转载 作者:行者123 更新时间:2023-12-05 00:56:01 25 4
gpt4 key购买 nike

问题

我正在尝试用PureScript编写游戏引擎。我是新手,但是自从我之前经历过真实世界的Haskell(尽管我也没有太多使用Haskell处理“真实”事物的经验)以来,学习一直很顺利。在我的书中,将我的运行时错误尽可能多地转换为编译时错误的任何事情都是成功的-但是,如果该语言被证明过度限制了我抽象问题的能力,那么它可以消除一些胜利。

好的,因此,我正在尝试在HTML5 Canvas / context2d上的PureScript中构建2d游戏引擎(显然purescript-canvas为此提供了一个不错的选择-我更喜欢Elm的Graphics.Canvas模块,因为它映射了很多更接近实际的基础JS API,尤其是让我可以访问Canvas的各个像素。

在我现有的(未完成但可用的)JS引擎中,核心功能是我保留一个“ sprite”列表(异类,但它们都共享一个公共类),然后遍历它们以调用.update(timeDelta).draw(context2d)方法。

所有的精灵都有一个共同的接口,但是必须在底层支持根本不同的数据。一个可能具有x / y坐标;另一个(可能表示环境效果)可能具有“完成百分比”或其他动画状态。

问题是,我只是无法提出一个等效的抽象(到异类/共享类列表)来完成我需要做的事情,而又不会滥用FFI将我的方式破解成非常不纯净的代码。

解决方案(及其问题)

异构列表(duh)

显然,可以等效于异构列表的最佳抽象方法就是异构列表。

哈斯克尔风格

事实证明,Haskell(即欺骗性的GHC,而不是正式的规范/报告)提供了exactly what I want-您可以在保留类型约束的同时装箱类型信息,对列表中的所有项目应用单个多态函数,而无需突破型安全。这将是理想的选择,但是可惜PureScript目前不允许我表达如下类型:

data ShowBox = forall s. Show s => SB s


PureScript样式(最新技术)

对于PureScript,有一个 purescript-exists软件包,该软件包可能旨在立即提供与以上Haskell解决方案相同的功能,并且可以让我(不是隐藏,而是删除)类型信息,然后将其重新放回原处。这将使我得到一个异构列表,但以完全破坏类型安全为代价。

更重要的是,我认为我无法让它满意,因为即使我有 [Exists f]列表,也不能只是将类型提取/重新添加为通用 forall a. (Draw a) => a,我必须知道我要恢复的实际类型。我可以包含某种“标记”,告诉我应该提取哪种“真实”类型,但是如果我要提取这些类型的恶作剧,那么我也可能会用普通的JS进行编码。我可能要做的事情(对于列表,不一定是包含的精灵)。

全部集中在一个海量数据中

我可以通过在一个大型结构中表示单个精灵的所有状态,并将其传递给每个精灵的“更新”实现,来统一所有精灵的类型(仍然不能使用类多态,但是我可以包含一个变异函数将每个单独的Sprite值都用作该类型的一部分,并使用该值)。这很明显是有原因的:每个子画面都可以自由更改/更新其他子画面的数据。对于我必须代表的每种新的精灵状态,都必须全局更新海量数据结构。无法建立它的库,因为使用引擎的每个人都必须对其进行修改。最好是JS。

单独的均匀状态类型

或者每个子画面可以具有单独的状态,并且所有子画面都具有相同的状态表示形式。这样可以避免出现“互相指责”的情况,但是我仍然需要一个统一的结构,我必须对每个Sprite的需求有足够的了解来进行更新,不需要大量的数据来浪费这些类型结构的位每个精灵非常差的抽象。

表示JSON中的不同数据或您拥有什么

w这种方法基本上只是使用JS数据并假装为PureScript。必须舍弃PureScript输入的所有优势。

没有抽象

我可以将它们全部视为完全无关的类型。这意味着,如果要添加新的精灵,则必须更新最外面的 draw函数以为最外面的 drawThisParticularSprite函数添加 update同上。在所有可能的解决方案中可能是最糟糕的。

我可能会做什么

假设我对可用的抽象选择的评估是正确的,似乎很明显,我将不得不以某种方式滥用FFI来完成所需的工作。也许我会有一个统一的记录类型,例如

type Sprite = { data: Data, draw: Data -> DrawEffect, update: Data -> Data }


其中 Data是一些类型不合常规的东西,例如某种 Exists f,并且

type DrawEffect = forall e. Eff (canvas :: Canvas | e) Context2D


或者其他的东西。 drawupdate方法都将特定于各个记录,并且都“知道”要从 Data中提取的真实类型。

同时,我可能会向PureScript开发人员询问支持Haskell风格的存在性东西的可能性,这样我就可以在不破坏类型安全性的情况下获得正确的,真正的异构列表。我认为主要的问题是(对于 Haskell example previously linked), ShowBox必须存储其(隐藏的)成员的实例信息,因此,它会从其 Show中知道要使用的 show正确实例。自己对 函数的替代。

恳求

有人可以从PureScript当前可用的选项中确认以上内容是否正确吗?我希望您进行任何更正,尤其是如果您看到一种更好的方法来解决此问题,尤其是如果有一种方法可以让我仅使用“纯”代码而不牺牲抽象性的话,请告诉我!

最佳答案

我在这里假设您的Draw类看起来像

class Draw a where
draw :: a -> DrawEffect
update :: a -> a


purescript-exists选项可以工作,并且绝对是类型安全的,尽管您声称要删除而不是隐藏信息。

您需要将对类的操作移动为一种类型:

data DrawOps a = DrawOps { "data" :: a
, draw :: a -> DrawEffect
, update :: a -> a
}


现在,您想要的类型是 Exists DrawOps,可以将其放入列表中,例如:

drawables :: List (Exists DrawOps)
drawables = fromArray [ mkExists (DrawOps { "data": 1
, draw: drawInt
, update: updateInt
}
, mkExists (DrawOps { "data": "foo"
, draw: drawString
, update: updateString
}
]


您可以使用 runExists(安全)解开类型,请注意 runExists的类型会强制您忽略包装数据的类型:

drawAll :: List (Exists DrawOps) -> DrawEffect
drawAll = traverse (runExists drawOne)
where drawOne (DrawOps ops) = ops.draw ops."data"


但是,如果这些是类中唯一的操作,则可以使用同构类型

data Drawable = Drawable { drawn :: DrawEffect
, updated :: Unit -> Drawable
}


想法是这种类型表示 DrawOps中的操作的展开:

unfoldDrawable :: forall a. DrawOps a -> Drawable
unfoldDrawable (DrawOps ops)
= Drawable { drawn: ops.draw ops."data"
, updated: \_ -> unfoldDrawable (DrawOps (ops { "data" = ops.update ops."data" }))
}


现在,您可以使用包含不同类型数据的 Drawable内容填充列表:

drawables :: List Drawable
drawables = fromArray [ unfoldDrawable 1 drawInt updateInt
, unfoldDrawable "foo" drawString updateString
]


同样,您可以安全地解开类型:

drawAll :: List Drawable -> DrawEffect
drawAll = traverse drawOne
where drawOne (Drawable d) = d.drawn

updateAndDrawAll :: List Drawable -> DrawEffect
updateAndDrawAll = traverse updateAndDrawOne
where updateAndDrawOne (Drawable d) = (d.updated unit).drawn

关于purescript - 适当的抽象代替异构(但共享类)列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36992410/

25 4 0
文章推荐: angularjs - "Failed to instantiate module ui.router"
文章推荐: regex - 使用 Perl 验证年份范围
文章推荐: sql-server - 将 ms access 驱动的站点从 sql server 移动到 jabry.com - 连接字符串问题
文章推荐: css - 在
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com