F代数的状态实现

Stateful implementation of F-algebra

考虑以下简单的 F 代数

trait Test[F[_]] {
  def add(i: Int): F[Unit]
}

我想提供它的实现来跟踪所有添加的值并添加那些尚未添加的值。它必须以线程安全的方式完成。

我能想到的“最佳”实现是使用 MVar[F, Ref[F, List[Int]]]。这是它的样子

def statefulMutexTest[F[_]: Concurrent] = {
  val mvarRef: F[MVar[F, Ref[F, List[Int]]]] =
    for {
      ref  <- Ref.of[F, List[Int]](List.empty[Int])
      mvar <- MVar.of[F, Ref[F, List[Int]]](ref)
    } yield mvar

  mvarRef map { mvar =>
    new Test[F] {
      override def add(i: Int): F[Unit] =
        mvar.take.bracket(ref =>
          for {
            list    <- ref.get
            _       <- if (!list.contains(i)) ref.set(list :+ i) else Applicative[F].unit
          } yield ())(mvar.put)
    }
  }
}

它看起来很乱,但按预期工作。我最初想到使用 StateT,但我不喜欢将状态导出到客户端的想法。

基本上 Ref 是我通常在这种情况下使用的所有内容,Test 这里只是一个特定于域的包装器:

object Test {

  def of[F[_]: Sync]: F[Test[F]] =
    Ref.of[F, Set[Int]](Set.empty).map(ref => (i: Int) => ref.update(_ + i).void)
}