scala – 为什么延迟工厂方法在F的上下文中具有返回值
发布时间:2020-12-16 09:04:46 所属栏目:安全 来源:网络整理
导读:我正在查看cats.effect.concurrent.Deferred并注意到其伴随对象内的所有纯工厂方法都返回F [Deferred [F,A]],而不仅仅是Deferred [F,A] def apply[F[_],A](implicit F: Concurrent[F]): F[Deferred[F,A]] = F.delay(unsafe[F,A]) 但 /** * Like `apply` but
我正在查看cats.effect.concurrent.Deferred并注意到其伴随对象内的所有纯工厂方法都返回F [Deferred [F,A]],而不仅仅是Deferred [F,A]
def apply[F[_],A](implicit F: Concurrent[F]): F[Deferred[F,A]] = F.delay(unsafe[F,A]) 但 /** * Like `apply` but returns the newly allocated promise directly instead of wrapping it in `F.delay`. * This method is considered unsafe because it is not referentially transparent -- it allocates * mutable state. */ def unsafe[F[_]: Concurrent,A]: Deferred[F,A] 为什么? 抽象类定义了两个方法(文档省略): abstract class Deferred[F[_],A] { def get: F[A] def complete(a: A): F[Unit] } 因此,即使我们直接分配Deferred,也不清楚如何通过其公共方法修改Deferred的状态.所有修改都以F [_]暂停. 解决方法
问题不在于F中是否暂停了变异,而是Deferred.unsafe是否允许您编写不是引用透明的代码.考虑以下两个程序:
import cats.effect.{ContextShift,IO} import cats.effect.concurrent.Deferred import cats.implicits._ import scala.concurrent.ExecutionContext implicit val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global) val x = Deferred.unsafe[IO,Int] val p1 = x.complete(1) *> x.get val p2 = Deferred.unsafe[IO,Int].complete(1) *> Deferred.unsafe[IO,Int].get 这两个程序不等价:p1将计算1,p2将永远等待.我们可以构造这样的示例这一事实表明Deferred.unsafe不是引用透明的 – 我们不能用引用自由地替换对它的调用,最终得到相同的程序. 如果我们尝试使用Deferred.apply做同样的事情,我们会发现我们不能通过用值替换引用来提出成对的非等价程序.我们可以试试这个: val x = Deferred[IO,Int] val p1 = x.flatMap(_.complete(1)) *> x.flatMap(_.get) val p2 = Deferred[IO,Int].flatMap(_.complete(1)) *> Deferred[IO,Int].flatMap(_.get) …但是这给了我们两个相同的程序(都挂起).即使我们尝试这样的事情: val x = Deferred[IO,Int] val p3 = x.flatMap(x => x.complete(1) *> x.get) …所有参考透明度告诉我们,我们可以将该代码重写为以下内容: val p4 = Deferred[IO,Int].flatMap(x => x.complete(1) *> x.get) …这相当于p3,所以我们再也没有打破参考透明度. 当我们使用Deferred.apply时,我们无法在F的上下文之外获得对可变Deferred [IO,Int]的引用这一事实特别在于保护我们. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |