首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >IORef的用法正确吗?

IORef的用法正确吗?
EN

Stack Overflow用户
提问于 2015-05-30 12:22:36
回答 1查看 274关注 0票数 1

目标是要求person输入一个整数,并验证它确实是一个整数。如果不是,那就再问一遍。第一次尝试是使用ioMonad.whileM,,因为它实际上在IO中返回值,并编写类似的内容(然后我们可以“安全地”将字符串转换到Int):

代码语言:javascript
复制
 val input: IO[Option[String]] = ioMonad.whileM(readLn.map(_ exists notDigit),
 askAndReadNumber)(scalaz.std.AllInstances.optionInstance)

但是这种方法没有奏效,因为在这种情况下,我不仅要验证值,而且还要再次从控制台读取它。

因此,由于我需要读取输入,然后以某种方式将其传递给条件,所以我想,IORef可能正是正确的工具(我以前从未使用过它,因此将这看作是我学习函数式编程的一种谦卑尝试)。我最后得到的是:

代码语言:javascript
复制
def requireNumber: IO[Int] = {    
    val numref: IO[IORef[String]] = newIORef("a")
    ioMonad.whileM_(condition(numref), askAndReadNumberToIORef(numref))
    numref.flatMap(_.read).map(_.toInt)
  }

  def condition(num: IO[IORef[String]]): IO[Boolean] = for {
    ref ← num
    enteredNumber ← ref.read
  } yield enteredNumber exists notDigit

  def askAndReadNumberToIORef(num: IO[IORef[String]]): IO[Unit] = for {
    ref ← num
    input ← askAndReadNumber
    _ ← ref.write(input)
  } yield ()

  private def notDigit: (Char) ⇒ Boolean =
    !Character.isDigit(_)

  def askAndReadNumber: IO[String] =
    for {
    _ ← putStrLn("Enter a number please")
    maxN ← readLn
  } yield maxN

实际上,整个循环都被完全忽略了,程序直接进入到带有初始引用的行:

代码语言:javascript
复制
num.flatMap(_.read).map(_.toInt)

那么,我是否在这里误用了Ref概念?为什么不起作用?

谢谢

更新:实际上通过编写以下方法解决了最初的问题:

代码语言:javascript
复制
def whileMpropagating[M[_], A](f: ⇒ M[A])(p: A ⇒ Boolean)(implicit M: Monad[M]): M[A] =
    M.bind(f)(value ⇒ if (!p(value)) f else whileMpropagating(f)(p))

然后是whileMpropagating(askAndReadNumber)(_ forall notDigit)(ioMonad) map (_.toInt)

但是我仍然对在这里使用IORef感兴趣。

Update2: My羞耻,iterateWhile in Monad做得非常精确:)

EN

回答 1

Stack Overflow用户

发布于 2015-05-31 18:05:45

IORef对你的案子太过分了。这是几行代码中的解决方案:

代码语言:javascript
复制
import scala.util.Try
import scalaz.effect.IO
import scalaz.syntax.monad._

private def isInteger(str: String) = Try(Integer.parseInt(str)).isSuccess

val requireNumber: IO[Int] = IO.readLn.iterateUntil(isInteger).map(Integer.parseInt)

IORef表示一个可变的引用(函数式编程试图避免这种引用),并且应该非常谨慎地使用它。通过尝试首先编写纯函数来解决问题总是一个好主意。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30546112

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档