设置:
我有几个不同数据结构的集合,它们代表虚拟系统中模拟对象的状态。我还有许多函数可以转换这些对象(即基于原始和 0 个或更多参数创建对象的新副本)。
目标是允许用户选择一些对象来应用转换(在模拟规则内),将这些函数应用于这些对象,并通过用新对象替换旧对象来更新集合。
我希望能够通过将较小的转换组合成较大的转换来构建这种类型的功能。然后评估这个组合函数。
问题:
如何构建我的程序以使这成为可能?
我用什么样的组合器来建立这样的交易?
想法:
- 将所有的收藏品放在一个巨大的结构中,然后传递这个结构。
- 使用状态单子完成基本相同的事情
- 使用 IORef(或其更强大的表亲之一,如 MVar)并建立一个 IO 操作
- 使用功能响应式编程框架
1 和 2 似乎携带了很多包袱,特别是如果我设想最终将一些集合移动到数据库中。(该死的 IO Monad)
3 似乎运行良好,但开始看起来很像重新创建 OOP。我也不确定在什么级别使用 IORef。(例如IORef (Collection Obj)
或Collection (IORef Obj)
或data Obj {field::IORef(Type)}
)
4 在风格上感觉是最实用的,但它似乎也创造了很多代码复杂性,而在表现力方面却没有太多回报。
例子
我有一个网上商店。我维护了一系列产品,其中包括(除其他外)库存数量和价格。我也有一些对商店有信誉的用户。
一位用户过来并选择了 3 种产品购买并使用商店信用结账。我需要创建一个新产品系列,减少 3 种产品的库存量,创建一个新的用户系列,并借记用户帐户。
这意味着我得到以下信息:
checkout :: Cart -> ProductsCol -> UserCol -> (ProductsCol, UserCol)
但后来生活变得更加复杂,我需要处理税收:
checkout :: Cart -> ProductsCol -> UserCol -> TaxCol
-> (ProductsCol, UserCol, TaxCol)
然后我需要确保将订单添加到运输队列中:
checkout :: Cart
-> ProductsCol
-> UserCol
-> TaxCol
-> ShipList
-> (ProductsCol, UserCol, TaxCol, ShipList)
等等……
我想写的是
checkout = updateStockAmount <*> applyUserCredit <*> payTaxes <*> shipProducts
applyUserCredit = debitUser <*> creditBalanceSheet
但是类型检查器会让我中风。我如何构建这个商店,使checkout
orapplyUserCredit
函数保持模块化和抽象?我不可能是唯一一个有这个问题的人,对吧?