读写状态单子 - 如何运行这个Scala代码

18

Tony Morris在这个代码片段中发表了一篇演讲。

他使用ReaderWriterState monad来提供对隐式上下文的受控读写访问。这是有意义的。

我该如何使用这段代码?我想看到一个使用此monad的示例“main”程序。


4
这篇Gist的评论中有一个示例链接:https://gist.github.com/2364137。我会将其翻译成:这个Gist的评论中有一份相关示例链接:https://gist.github.com/2364137。 - Ben James
为了理解如何使用这个Monad,可以将示例中的for (...) yield {}转换为flatMap和map,并查看隐式定义以实现Monoid Trait(id和op方法)和Functor Trait(fmap)。 - fp4me
1个回答

19

Scalaz 7现在提供了这个单子,下面是一个完整的工作示例,翻译自上面评论中链接的Michael Pilquist的示例,进行了少量修改。

package scalaz.example

import scalaz._, Scalaz._


object RWSExample extends App {
  case class Config(port: Int)

  def log[R, S](msg: String): ReaderWriterState[R, List[String], S, Unit] =
    ReaderWriterStateT {
      case (r, s) => (msg.format(r, s) :: Nil, (), s).point[Id]
    }

  def invokeService: ReaderWriterState[Config, List[String], Int, Int] =
    ReaderWriterStateT {
      case (cfg, invocationCount) => (
        List("Invoking service with port " + cfg.port),
        scala.util.Random.nextInt(100),
        invocationCount + 1).point[Id]
    }

  val program: RWS[Config, List[String], Int, Int] = for {
    _ <- log("Start - r: %s, s: %s")
    res <- invokeService
    _ <- log("Between - r: %s, s: %s")
    _ <- invokeService
    _ <- log("Done - r: %s, s: %s")
  } yield res

  val (logMessages, result, invocationCount) = program run (Config(443), 0)
  println("Result: " + result)
  println("Service invocations: " + invocationCount)
  println("Log: %n%s".format(logMessages.mkString("\t", "%n\t".format(), "")))
}

本文是针对Scalaz 7.2.18进行的测试,该版本可以作为Maven或SBT依赖项轻易地从Maven中央仓库获取


我看不出 Random.nextInt 在哪里适用...它并没有返回到 invocationCount 中,所以为什么不只是 Unit?或者是0? - Jimmy Hoffa
1
使用Scala 7.2,上述代码需要进行修改。将“Identity”替换为“Id”。此行不再编译:val Need(logMessages, result, invocationCount) = program run (Config(443), 0),但我不了解足够的Scala或Scalaz来解释原因。 - MrMeritology
// 下面这行代码对我有用 val (logMessages, result, invocationCount) = program run (Config(443), 0) - Mohan Narayanaswamy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接