使用Scala类型系统防止托管类型组合器

时间:2017-10-29 16:55:55

标签: scala functional-programming

考虑以下组合器用于包装有效计算的仿函数:

def bracket[F[_]: Effect, A, R](alloc: F[R])(use: R => F[A], release: R => F[Unit]): F[A]
可以假设

Effect是有效仿函数的合适类型类。 Effect的确切实施无关紧要,但举一个具体的例子,请考虑https://github.com/typelevel/cats-effect

中的cats.effect.IO

该组合器旨在安全地对use的评估进行排序和释放外部资源R,这可能会产生大量的创建,破坏或维护成本。如果use表示运行时故障,则不评估alloc。无论release中表达的任何运行时故障,都会评估use。在评估R之后,release的剩余可寻址的延迟实例被认为是完全无法使用的,并且代表了已释放的资源。

正如这里所写,bracket组合器是不安全的。考虑:

/** Holds a real world mutable and/or expensive resource. */
type OpenThing

def allocExpensive[F[_]: Effect]: F[OpenThing] = ???
def releaseRuntime(ot: OpenThing): F[Unit] = ???

def leaks[F[_]: Effect] =
    bracket[F, R, R](allocExpensive[F])
                    ((r: R) => Effect[F].pure(r), 
                     (r: R) => releaseRuntime(r))

def breaks[F[_]: Effect]: F[Doom] =
    for {
        deadRef <- leaks[F]
    } yield deadRef.totallyIllegal

此示例编码非常直接的不安全用法,但显然可能有更微妙的版本,其中A =:= R不成立,但A嵌入,关闭或以其他方式维护指向死资源句柄的链接在R内找到。

我的问题:

有没有办法更改bracket的签名以防止泄露R的实例?

或者如果使用bracket类似于:

def withOpenThing[F[_], A](job: OpenThing => F[A]): F[A] =
    bracket[F, A, OpenThing](allocExpensive[F])(job, releaseRuntime)

是否有一种构建OpenThing的方法可以阻止它在A中被引用?

整个努力对我来说似乎是一个很长的镜头,但Scala类型系统中的东西比我虚弱想象中的梦想更多。

0 个答案:

没有答案