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