我正在寻找这样一种类型,它允许我代表一个上下文,其中运行一段代码。例如:
def withinContext[R]: ((=> R) => R) =
(inner) => {
initializeSomeResource()
try {
inner
} finally {
releaseTheResource()
}
}
然后我可以简单地用作
withinContext {
...
}
或者,如果内部代码块需要来自上下文的一些信息,则将其概括为
def withinContext[R]: ((Ctx => R) => R) = ...
他们的用例大致对应于Haskell的bracket_
和bracket
。
我可以直接使用类型(=> R) => R
和(A => R) => R
,但是我没有用于组合这些上下文包装器的实用程序函数,所以我想,是否存在类似于Scala生态系统?
我知道的关闭事件是scala.util.control.Exception.Catch
,它为构造和组合Catch
实例提供了很好的函数,但是在内部块执行之前似乎没有办法运行任何初始化。另外(这对我的用例来说并不重要)它不允许为内部计算提供参数,就像(A => R) => R
一样。
类型(A => R) => R
是延续monad,对应于Haskell的ContT r IO a
,但我无法在任何标准Scala库中找到continuation monad的实现(也许它& #39; s隐藏在斯卡拉兹深处,我错过了它。)
答案 0 :(得分:0)
我经常使用这种方法与Specs2测试代码一起使用。基本上我们希望设置一些上下文来包围代码块。我使用的成语是这样的:
def contextName[TYPE,RSRC](doit: (RSRC) => TYPE) : TYPE = {
val thing : RSRC = acquireResource(args)
try doit(thing)
finally releaseResource(thing)
}
我意识到你正试图继续延续,但我不得不问:为什么?我刚刚给出的成语是类型的连续monad(RSRC => TYPE)=> TYPE,它可以像您在withContext
中建议的那样使用。例如,我写的ReactiveMongo上下文对象的实际用例:
def withDatabase[T](dbName: String)(doit: (DefaultDB) => T) : T = {
val db = connection.db(dbName)
try doit(db)
finally db.drop()
}
这将获取一个数据库,将其传递给continuation,然后在完成后删除数据库,即使continuation抛出异常也是如此。它被这样使用:
val numCollections = withDatabase("foo") { db =>
db.collectionNames.map { list => list.size }
}
其中只使用数据库来获取数据库中的(未来)数量的集合。
希望这有帮助。