我正在呼叫一个数据库(EventStore),建议在应用程序的整个生命周期中使用相同的连接。我想为此实现一个缓存调用,但是我唯一发现的就是以这种方式存储备忘录(lib io-memoize):
import Database.EventStore
import System.IO.Memoize
getCachedEventStoreConnection :: Settings -> ConnectionType -> IO (IO (Connection))
getCachedEventStoreConnection settings connectionType = once $ connect settings connectionType
我想要的是更多这样的签名:
getCachedEventStoreConnection ::设置-> ConnectionType-> IO连接
否则,我必须将IO(IO(连接))作为“全局函数”保存,这是我在各处传递的,这不利于模块化...
答案 0 :(得分:3)
否则,我必须将IO(IO(连接))保留为“全局功能”,这是我在各处传递的,这不利于模块化。
不幸的是,缓存调用无助于消除函数参数:与其传递缓存的结果,不如传递缓存的结果。没有解决的办法。选择Haskell时所穿的衬衫的一部分是 all ,函数必须使用其类型明确的数据,因此,如果应用程序的一部分需要数据库Connection
,除了将Connection
传递到应用程序的那部分(以及扩展名,它的所有调用方)之外,没有其他用途。
有一些糖,例如ReaderT
,您可以撒些糖来使事情变得更方便,使其看起来好像您没有在传递函数参数一样,但是到最后,这正是它们的含义在幕后做。
但是,我拒绝您的说法,这不利于模块化。如果 did 具有隐式缓存,则将 break 模块化:您将无法将该功能从该应用程序中移出到库中,并且无法在许多应用程序中使用它而没有还将缓存移出。也就是说,缓存和使用它的任何操作都将耦合在一起-必须取消全部或全部取消,这与模块化完全相反。*如果数据库连接是函数参数而不是隐式缓存,则可以独立地取消缓存在应用启动时取消一次创建连接的代码块。
*并且假设您确实将所有操作和隐式缓存放入库中。现在,有两个下游库依赖并使用您的库。您是否获得了两个必须分别初始化的缓存,因此效率可能较低;或者您是否获得了一个共享缓存,因此将效果从一个库泄漏到另一个库中,因此可能不太正确?一个艰难的选择-应该由下游用户而不是由其中装有缓存的库来仔细而明确地做出选择。