scala - 仅使用 IO monad 中的值,无需先行 IO 操作

标签 scala io monads scalaz

在做一些家庭项目时,我遇到了一种感兴趣的效果,现在,这对我来说似乎是显而易见的,但我仍然没有找到摆脱它的方法。 这就是要点(我正在使用 ScalaZ,但在 haskell 中可能会有相同的结果):

def askAndReadResponse(question: String): IO[String] = {
  putStrLn(question) >> readLn
}

def core: IO[String] = {
  val answer: IO[String] = askAndReadResponse("enter something")
  val cond: IO[Boolean] = answer map {_.length > 2}
  IO.ioMonad.ifM(cond, answer, core)
}

当我尝试从core获取输入时,askAndReadResponse会评估两次 - 一次用于评估条件,然后在ifM中(所以我会在必要时再次收到该消息和 readLn )。 我需要什么 - 只是经过验证的值(例如稍后打印)

是否有任何优雅的方法可以做到这一点,特别是 - 进一步传递 IO 结果,而不需要前面的 IO 操作,即避免执行 askAndReadResponse 两次?

最佳答案

您可以使用带有 flatMap 的单子(monad)绑定(bind)对效果进行排序:

def core: IO[String] = askAndReadResponse("enter something").flatMap {
  case response if response.length > 2 => response.point[IO]
  case response => core
}

这可以让您获取一次计算的结果(用户在提示后输入文本)并将其用于后续计算(是否返回或循环的计算,以及如果返回则结果)。

ifM 只是在您的情况下没有用处 - 仅当您的条件和成功的分支是独立计算时它才适用。

关于scala - 仅使用 IO monad 中的值,无需先行 IO 操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33087966/

相关文章:

scalaz.concurrent.Task RepeatEval 仅评估 Task.now 和 Task.async 一次

scala - 如何在Spark中将矩阵转换为RDD [Vector]

java - 检查文件是否已完全写入

android - 在 cordova 混合 android 应用程序中写入/读取文件

scala - 如果使用 cats IO 选项为 None,如何停止 for-compression 的执行?

Haskell,forM - 为什么这段代码返回这样的结果?

scala - 如何证明Scala中的爆炸原理(ex falso sequitur quodlibet)?

scala - 为什么Scala不从泛型类型参数推断类型?

c# - IO 101 : Which are the main differences between TextWriter, FileStream 和 StreamWriter?

java - 这是 Clojure 中可变状态的明智单子(monad)吗?