【问题标题】:Scala state monad in for comprehension用于理解的 Scala 状态单子
【发布时间】:2013-10-08 09:42:28
【问题描述】:

我正在学习 Michael Pilquist 的优秀状态单子讲座here。我在 54 分钟时遇到了两个问题。

  1. 如果ofsOption[FollowerStats],那么? 运算符是什么?一世 在 Scala 2.10.2 中的 Option 上找不到三元运算符

  2. 最后一个生成器如何将更新的缓存(命中或未命中递增)放回 checkCache 方法的State 结果中?返回的State 似乎被丢弃了,for 理解似乎只产生了Option[FollowerStats]

.

def checkCache(u: String): State[Cache, Option[FollowerState]] = for {
    c <- State.get[Cache]
    ofs <- State.state {
        c.get(u).collect {
            case Timestamped(fs, ts) if !state(ts) => fs
        }
    }
    _ <- State.put(ofs ? c.recordHit | c.recordMiss)
} yield ofs

为了尝试理解,我尝试重写 for 理解,但没有帮助。

State.get[Cache].flatMap{ c => 
    State.state{c.get(u).collect(...)}.flatMap{ ofs =>
        State.put(ofs ? c.recordHit | c.recordMiss).map{ _ =>
            ofs
        }
    }
}

更新: 多亏了答案,我想我已经掌握了第 2 点的关键。我没有意识到 yield 本质上是在说:从put 中取出最后一个状态s =&gt; (s,()) 并将Unit 值类型替换为ofs,得到s =&gt;(s,ofs)。我想关键是要意识到 yield 并不是字面上的返回 ofs,而是被翻译为 State.map。

更新 现在了解选项位。我猜这个演示文稿仍然使用了 Scalaz 的隐式,尽管它派生了 state monad。

【问题讨论】:

  • Option ? ... | ... 位来自隐式转换(特别是隐式类OptionOps)。您可能已经处理过隐式转换,例如由于隐式转换为StringOps 而能够在字符串上调用toInt - 这几乎相同。
  • 在 1:06:12 他实际上提到了选项的事情。应该继续观看,但强迫症阻止了它。
  • 希望下一个观看该视频的强迫症患者会发现这个问题,阅读所有的 cmets,并知道直接跳回去观看视频的其余部分! :)

标签: scala monads scalaz state-monad


【解决方案1】:

首先是三元运算符。

ofs ? c.recordHit | c.recordMiss

相当于:

if (ofs.isDefined) c.recordHit else c.recordMiss

或者:

ofs.fold(c.recordMiss)(_ => c.recordHit)

它由 Scalaz 提供并实现为隐式类 (OptionOps),该类为 Option 提供 ? 方法,该方法返回具有 | 方法的 Conditional 类。在这种情况下,我不确定额外的简洁是否值得混淆,但人们使用它,所以值得了解。

对于状态更新,请考虑以下简化示例:

val inc: State[Int, Unit] = for { i <- get[Int]; _ <- put(i + 1) } yield ()

乍一看,我们似乎在“丢弃”状态并且只生成单元,但 inc 的值实际上是整个状态操作计算(在这种情况下,它不返回任何相关或有趣的值),包括更新。

【讨论】:

    【解决方案2】:
    1. ?| 运算符来自 scalaz 的布尔语法。看看here at BooleanOps。它实际上是 2 个函数,首先是 ?,然后是 | Conditional

    2. 更新的缓存实际上是运行State 操作的结果。如果您在视频前面看,State 应该被定义为,给定状态动作和初始状态 s,使用 s 运行状态动作会产生 (a, s2),这是一对: (a) 从传入状态计算的值(在元组中表示为 a)和 (b) 执行操作后的新状态(表示为 s2)。

    请注意,新的Cache 直到通过一元操作运行初始Cache 时才实际计算。

    【讨论】:

    • 这是OptionOps 上的?,而不是BooleanOps
    • @TravisBrown 太真实了!道歉。
    猜你喜欢
    • 1970-01-01
    • 2017-10-11
    • 1970-01-01
    • 2019-12-13
    • 1970-01-01
    • 1970-01-01
    • 2016-04-05
    • 2014-06-07
    • 2011-11-16
    相关资源
    最近更新 更多