【发布时间】:2011-06-14 16:44:01
【问题描述】:
我正在寻找一个通用模块,允许 Haskell 程序与 Cassandra 交互。模块需要维护自己的状态。例如,它将有一个连接池和一个在保存新记录时要调用的回调列表。我应该如何构造代码以便该模块可以保持其状态?以下是我一直在考虑的一些方法。我在正确的轨道上吗? (我是 Haskell 的新手,仍在学习函数式思考的最佳方法。)
选项 1:
模块在 (StateT s IO) monad 中运行,其中 s 是使用 Cassandra 模块的整个程序的全局状态。当然,由于 Cassandra 模块可以被多个程序使用,所以 s 中的内容的详细信息应该对 Cassandra 模块是不可见的。该模块必须导出一个类型类,使其能够从 s 中提取 CassandraState 并将新的 CassandraState 推回 s 中。然后,任何使用该模块的程序都必须使其主状态成为该类型类的成员。
选项 2:
模块在 (StateT CassandraState IO) monad 中运行。每次有人在模块中调用一个操作时,他们都必须从他们隐藏的任何地方提取 CassandraState,使用 runState 调用该操作,然后获取结果状态并再次将其隐藏(无论在哪里)。
选项 3:
根本不要将 Cassandra 模块的函数放在 StateT monad 中。相反,让调用者在需要时显式传递 CassandraState。选项 2 的问题是,并非模块中的所有函数都会修改状态。例如,获取连接将修改状态,并要求调用者隐藏结果状态。但是,保存新记录需要读取状态(以获取回调),但不需要更改状态。选项 2 不会给调用者任何暗示 connect 会改变状态,而 create 不会。
但是,如果我不再使用 StateT monad,而只使用将状态作为参数并返回简单值或简单值和新状态的元组的函数,那么当状态需要时调用者会很明显得救了。 (在我的模块中,我会获取传入的状态并将它们构建到一个 (StateT CassandraState IO) monad 中,但是这个细节将对调用者隐藏。所以,对于调用者来说,接口是非常明确的,但在幕后,它只是选项 2。)
选项 4:
还有什么?
在构建可重用模块时,这个问题必须经常出现。有什么标准的方法可以解决吗?
(顺便说一句,如果有人知道从 Haskell 与 Cassandra 交互比使用 Thrift 更好的方法,请告诉我!也许我根本不需要写这个。:-)
【问题讨论】:
-
仅供参考 - 在 Haskell 圈子中,“模块”是编译单元,即 - 单个源文件。尽管对于您所描述的内容,我真的没有更好的名词,但谈到具有状态的“模块”时,我还是有一段时间。
-
糟糕。我应该说“包”或“库”。
标签: haskell