你如何构建Haskell中的有状态模块?

我正在寻找一个允许Haskell程序与Cassandra进行交互的通用模块。 该模块将需要保持自己的状态。 例如,它将有一个连接池和一个保存新记录时调用的回调列表。 我应该如何构造代码以便该模块能够保持其状态? 以下是我一直在考虑的一些方法。 我在正确的轨道上吗? (我是Haskell的新手,仍然在学习从功能上思考的最佳方法。)

选项1:

该模块在(StateT IO)monad中运行,其中s是使用Cassandra模块的整个程序的全局状态。 当然,由于Cassandra模块可以被多个程序使用,因此Cassandra模块的细节应该是不可见的。 该模块必须导出一个允许从s中提取CassandraState的类型类,并将新的CassandraState推回到s中。 然后,使用该模块的任何程序都必须使其主要状态成为此类型的成员。

选项2:

该模块在(StateT CassandraState IO)monad中运行。 每当有人在模块中调用某个动作时,他们都必须从卡住的地方提取CassandraState,使用runState调用动作,然后获取结果状态并再次将其关闭(无论何处)。

选项3:

不要把Cassandra模块的函数放在StateT monad中。 相反,如果需要,调用者必须显式传入CassandraState。 选项2的问题是,并非模块中的所有功能都会修改状态。 例如,获取连接将修改状态,并要求调用方隐藏结果状态。 但是,保存新记录需要读取状态(获取回调),但不需要更改状态。 选项2不给调用者任何连接提示改变状态,而创建没有。

但是,如果我不再使用StateT monad,而只是具有将状态作为参数并返回简单值或简单值和新状态的元组的函数,那么对于调用者来说,何时需要保存状态。 (在我的模块的封面下,我将接收状态并将它们构建到一个(StateT CassandraState IO)monad中,但是对于调用者来说,这些细节将隐藏起来。因此,对于调用者来说,接口非常明确,但在封面下,它只是选项2)。

选项4:

还有别的吗?

构建可重用模块时,这个问题必须经常出现。 有没有某种标准的解决方法?

(顺便说一下,如果有人知道使用Haskell与Cassandra进行交互比使用Thrift更好的方式,请告诉我!也许我根本不需要写这个。:-)


像HDBC模型一样,应该有一个明确的CassandraConnection数据类型。 它有一个可变状态的MVar。 因为你所有的动作都是用IO来完成的,我想可以把CassandraConnection作为这些动作的参数。 然后,用户可以将该连接打包到状态或读取器monad中,或者将其明确地进行线程化,或者执行任何他们想要的操作。

在内部你可以使用monad或不使用 - 这真的是你的呼叫。 但是,我赞成在可能的情况下不会强制用户使用任何特定的monad,除非真正有必要。

所以这是选项3的一种版本。但用户不应该在乎他们是否正在改变连接状态 - 在那个级别上,你真的可以隐藏它们的细节。


我会选择使用选项2.你的模块的用户不应该直接使用runState ; 相反,你应该提供一个带有Monad类型类实例的不透明Cassandra类型和一些runCassandra :: Cassandra a -> IO a来“逃离”Cassandra的操作。 你的模块导出的操作都应该在Cassandra monad中运行(例如doSomethingInterestingInCassandra :: Int -> Bool -> Cassandra Char ),并且它们的定义可以访问包装的CassandraState

如果你的用户需要一些额外的应用程序状态,他们总是可以在Cassandra包装一个monad变换器,例如StateT MyState Cassandra

链接地址: http://www.djcxy.com/p/58753.html

上一篇: How do you structure a stateful module in Haskell?

下一篇: Which Boostrap3 grid mode for mobile/desktop do you use?