仅使用来自 IO monad 的值,没有先例 IO 操作

Use only the value from IO monad without precedent IO actions

在做一些家庭项目时,我遇到了一个有趣的效果,现在对我来说似乎很明显,但我仍然没有找到摆脱它的方法。 这就是要点(我正在使用 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 两次?

您可以使用 monadic 绑定对效果进行排序 flatMap:

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

这让你可以获取一次计算的结果(用户在提示后输入文本)并在后续计算中使用它(关于是否 return 或循环的计算,结果如果 returning).

ifM 对你的情况没有用——只有当你的条件和成功的分支是独立计算时它才会在这里起作用。