您如何在Haskell中构造有状态模块? [英] How do you structure a stateful module in Haskell?

查看:87
本文介绍了您如何在Haskell中构造有状态模块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm looking to write a generic module that allows Haskell programs to interact with Cassandra. The module will need to maintain its own state. For example, it will have a connection pool and a list of callbacks to be invoked when a new record is saved. How should I structure the code so that this module can maintain its state? Here are some of the approaches I've been considering. Am I on the right track? (I'm new to Haskell and still learning the best ways to think functionally.)

选项1:

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

The module runs in a (StateT s IO) monad, where s is the global state for the entire program using the Cassandra module. Of course, since the Cassandra module could be used by multiple programs, the details of what's in s should be invisible to the Cassandra module. The module would have to export a type class that allowed it to extract the CassandraState from s and push a new CassandraState back into s. Then, any program using the module would have to make its main state a member of this type class.

选项2:

该模块在(StateT CassandraState IO)monad中运行.每次有人在模块中调用动作时,他们都必须从藏有它的位置中提取CassandraState,使用runState调用该动作,并获取结果状态并将其再次隐藏(在任何地方).

The module runs in a (StateT CassandraState IO) monad. Every time someone calls an action in the module, they would have to extract the CassandraState from wherever they have it stashed off, invoke the action with runState, and take the resulting state and stash it off again (wherever).

选项3:

根本不将Cassandra模块的功能放在StateT monad中.而是让调用者在需要时显式传递CassandraState的值.选项2的问题在于,并非模块中的所有功能都会修改状态.例如,获得连接将修改状态,并且将要求调用者隐藏结果状态.但是,保存新记录需要读取状态(以获取回调),但不需要更改状态.选项2不会给调用者任何提示,连接可以改变状态,而创建则不能.

Don't put the Cassandra module's functions in a StateT monad at all. Instead, have the caller explicitly pass in CassandraState's when needed. The problem with option 2 is that not all of the functions in the module will modify the state. For example, obtaining a connection will modify the state and will require the caller to stash off the resulting state. But, saving a new record needs to read the state (to get the callbacks), but it doesn't need to change the state. Option 2 doesn't give the caller any hint that connect changes the state while create doesn't.

但是,如果我不再使用StateT monad,而只是使用将状态作为参数并返回简单值或简单值和新状态的元组的函数,那么当状态需要时,对于调用方来说确实很明显被保存下来. (在模块的内部,我将传入的状态构建为(StateT CassandraState IO)单子状态,但是此方法的详细信息对于调用者是隐藏的.因此,对于调用者而言,接口非常明确,但实际上是选项2.)

But, if I move away from using the StateT monad and just have functions that take in states as parameters and return either simple values or tuples of simple values and new states, then it's really obvious to the caller when the state needs to be saved off. (Under the covers in my module, I'd take the incoming states and build them into a (StateT CassandraState IO) monad, but the details of this would be hidden from the caller. So, to the caller, the interface is very explicit, but under the covers, it's just Option 2.)

选项4:

还有什么?

在构建可重用模块时,必须经常出现此问题.有某种标准的解决方法吗?

This problem must come up quite often when building reusable modules. Is there some sort of standard way to solve it?

(顺便说一句,如果有人比Hasthrell知道一种更好的与Haskell进行Cassandra交互的方法,请告诉我!也许我根本不必编写此代码.:-)

(By the way, if someone knows a better way to interact with Cassandra from Haskell than using Thrift, please let me know! Maybe I don't have to write this at all. :-)

推荐答案

诸如HDBC模型之类的东西将具有显式的CassandraConnection数据类型.它内部有一个MVar,具有某种可变状态.因为您的所有操作无论如何都在IO中,所以它们可以将CassandraConnection用作这些操作的参数.然后,用户可以将该连接打包到一个状态或读取器monad中,或显式地对其进行线程化,或执行他们想要的任何事情.

Something like the HDBC model would be to have an explicit CassandraConnection data type. It has an MVar inside with some mutable state. Since all your actions are in IO anyway I'd imagine, they can just take the CassandraConnection as an argument to these actions. The user then can pack that connection into a state or reader monad, or thread it explicitly, or do whatever they want.

在内部,您可以使用单声道,也可以不使用-这确实是您的要求.但是,我赞成API,除非确实有必要,否则在可能的情况下不要强迫用户进入任何特定的monad.

Internally you can use a monad or not -- that's really your call. However, I favor APIs that when possible don't force users into any particular monad unless truly necessary.

所以这是选项3的一种版本.但是,用户不必在乎是否更改连接状态-在那个级别上,您可以真正从中隐藏详细信息.

So this is a sort of version of option 3. But the user shouldn't really care whether or not they're changing the connection state -- at that level you can really hide the details from them.

这篇关于您如何在Haskell中构造有状态模块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆