【问题标题】:Stateful implementation of F-algebraF-代数的有状态实现
【发布时间】:2020-10-28 07:35:04
【问题描述】:

考虑以下简单的 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,但我不喜欢将状态导出给客户端的想法。

【问题讨论】:

  • AFAIK 这不是所谓的“F-代数”。这是“代数F”。 “F-代数”是F[A] =&gt; A,是关于组合/提取的,你有Int =&gt; F[Unit]
  • 为什么还要同时使用RefMVarRef 在你的情况下就足够了。
  • @MateuszKubuszok MVar 的原因是我想提供对状态的“互斥”访问(List[Int])。如果add 逻辑中涉及一些有效的计算,则似乎不可能将MVar 扔掉。
  • Ref already 提供互斥
  • 在这种情况下,我既不会看 Ref 也不会看 MVar,而是看 STM 实现,比如github.com/TimWSpence/cats-stm

标签: scala functional-programming scala-cats cats-effect


【解决方案1】:

基本上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)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-26
    • 1970-01-01
    • 2013-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-02
    相关资源
    最近更新 更多