【发布时间】:2012-01-22 08:06:21
【问题描述】:
设置:
我有几个不同数据结构的集合,它们代表虚拟系统中模拟对象的状态。我还有一些函数可以转换这些对象(即基于原始和 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 或applyUserCredit 函数保持模块化和抽象?我不可能是唯一一个有这个问题的人,对吧?
【问题讨论】:
-
只是要明确一点:您有各种类型类似于
A -> A的函数,用于各种特定类型A;您希望能够将它们组合成复合动作,更新某种共享状态;并且您不希望每个函数都知道处于共享状态的其他所有内容? -
C.A.McCann:正确;虽然有些可能需要通过柯里化从
B -> A -> A之类的东西派生出来。
标签: haskell data-modeling ioref