仅使用IO monad中没有先前IO操作的值

I S*_*ces 4 io monads scala 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)
}
Run Code Online (Sandbox Code Playgroud)

当我试图从中获取输入时core,askAndReadResponse评估两次 - 一次用于评估条件,然后用于ifM(因此我有消息,readLn然后再需要一次).我需要什么 - 只是验证的值(例如,稍后打印)

有没有优雅的方法来做到这一点,特别是 - 进一步传递IO的结果,没有先前的IO动作,即避免执行 askAndReadResponse两次?

Tra*_*own 6

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

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

这使您可以获取一次计算的结果(用户在提示后输入文本)并在后续计算中使用它(关于是返回还是循环的计算,以及返回时的结果).

ifM 只是在你的情况下不会有用 - 如果你的条件和成功的分支是独立的计算,它只会在这里工作.