Pet*_*lák 5 continuations scala
我正在寻找这样一种类型,它允许我表示一个上下文,其中运行一段代码.例如:
def withinContext[R]: ((=> R) => R) =
(inner) => {
initializeSomeResource()
try {
inner
} finally {
releaseTheResource()
}
}
Run Code Online (Sandbox Code Playgroud)
然后,我可以简单地使用
withinContext {
...
}
Run Code Online (Sandbox Code Playgroud)
或者,如果内部代码块需要来自上下文的一些信息,则将其概括为
def withinContext[R]: ((Ctx => R) => R) = ...
Run Code Online (Sandbox Code Playgroud)
他们的用例大致对应于Haskell bracket_和bracket.
我可以使用种类(=> R) => R和(A => R) => R直接,但后来我有这样的组合包装方面没有实用功能,所以我不知道,有没有像在斯卡拉生态系统中已经存在的东西吗?
我知道关闭的东西是scala.util.control.Exception.Catch,它为构造和组合Catch实例提供了很好的功能,但是在内部块执行之前似乎没有办法运行任何初始化.另外(这对我的用例来说不是那么重要)它不允许给内部计算提供参数,就像在这种情况下一样(A => R) => R.
类型(A => R) => R是延续monad,对应于Haskell ContT r IO a,但我找不到任何标准Scala库中的continuation monad的实现(也许它隐藏在Scalaz深处,我错过了它).
我经常这样做,以便与 Specs2 测试代码一起使用。本质上,我们希望设置一些上下文来包围代码块。我使用的习语是这样的:
def contextName[TYPE,RSRC](doit: (RSRC) => TYPE) : TYPE = {
val thing : RSRC = acquireResource(args)
try doit(thing)
finally releaseResource(thing)
}
Run Code Online (Sandbox Code Playgroud)
我知道你正试图延续一个延续,但我不得不问:为什么?我刚刚给出的习惯用法是 (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()
}
Run Code Online (Sandbox Code Playgroud)
它获取一个数据库,将其传递给延续,然后在完成后删除数据库,即使延续抛出异常。它的使用方式如下:
val numCollections = withDatabase("foo") { db =>
db.collectionNames.map { list => list.size }
}
Run Code Online (Sandbox Code Playgroud)
它只是使用数据库来获取数据库中(未来)数量的集合。
希望这可以帮助。