gpt4 book ai didi

scala - Ref/MVar 的有效更新

转载 作者:行者123 更新时间:2023-12-03 23:02:29 24 4
gpt4 key购买 nike

我想对 MVar 中的值进行有效计算或 Ref原子 更新它以防计算成功或放回初始值(在 MVar 的情况下)/在操作失败的情况下什么也不做(在 Ref 的情况下)。
一、引用案例

val ref = Ref.of[IO, Int](0)

def foo(i: Int): IO[Int] = //... some effectual computation
因为原子性很重要,而且 Ref不提供 compareAndSet不幸的是,操作必须明确实现,这看起来并不吸引人。
二、 MVar-case
MVar 提供了互斥语义,但问题在于 bracket不允许我们 put计算值。下面是一个例子:
val mvar = MVar.of[IO, Int](0)

def foo(i: Int): IO[Int] = IO(i + 1)

for {
mvar <- mvar
i <- mvar.take.bracket(foo)(mvar.put) //puts back 0, not 1
} yield ()
有没有办法至少为 MVar 实现这种行为?或 Ref ?
UPD :
我用 MVar 实现了它,但它看起来相当丑陋:
def updateAtomically(mvar: MVar[IO, Int], foo: Int => IO[Int]): IO[Int] = for {
i <- mvar.take
ii <- foo(i).onError{
case t => mvar.put(i)
}
_ <- mvar.put(ii)
} yield ii

最佳答案

您可以使用 MonadError.redeemWith 为了这:

def updateAtomically(mvar: MVar[IO, Int], foo: Int => IO[Int]): IO[Int] =
for {
i <- mvar.take
ii <- foo(0).redeemWith(_ => IO(i), ii => mvar.put(ii) *> IO(ii))
} yield ii
进而:
import cats.Applicative.ops.toAllApplicativeOps
import cats.effect.{ ExitCode, IO, IOApp }
import cats.effect.concurrent.MVar

object Foo extends IOApp {

def foo(i: Int): IO[Int] = IO(i + 1)
def fooBar(i: Int): IO[Int] = IO.raiseError(new RuntimeException("BOOM"))

def run(args: List[String]): IO[ExitCode] =
(for {
mvar <- MVar.of[IO, Int](0)
res <- updateAtomically(mvar, foo)
_ <- IO(println(res))
} yield res).map(_ => ExitCode.Success)
}
产量:
1
和:
def run(args: List[String]): IO[ExitCode] =
(for {
mvar <- MVar.of[IO, Int](0)
res <- updateAtomically(mvar, fooBar)
_ <- IO(println(res))
} yield res).map(_ => ExitCode.Success)
产量:
0

关于scala - Ref/MVar 的有效更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64765566/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com