1

目標は、人に整数を入力してもらい、それが実際に整数であることを確認することです。そうでない場合は、もう一度尋ねてください。最初の試みはioMonad.whileMを使用することでした。これは実際には IO 内で値を返し、そのようなものを記述したためです (そうすれば、String を Int に「安全に」キャストできます)。

 val input: IO[Option[String]] = ioMonad.whileM(readLn.map(_ exists notDigit),
 askAndReadNumber)(scalaz.std.AllInstances.optionInstance)

しかし、そのアプローチはうまくいきませんでした。なぜなら、この条件では、値を検証するだけでなく、コンソールからもう一度読み取ることもあるからです。

したがって、入力を読み取り、何らかの方法で条件に渡す必要があるため、IORefがまさに適切なツールである可能性があると考えていました (以前は使用したことがなかったので、関数型プログラミングを学ぶための謙虚な試みと考えてください)。 . 私はそれで終わった:

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

そして何が起こっているのか - 実際にはループ全体が完全に無視され、プログラムは最初の参照のある行に直接進みます:

num.flatMap(_.read).map(_.toInt)

では、ここでRefの概念を誤用しているのでしょうか。なぜ機能しないのですか?

ありがとう

更新: 実際には、このメソッドを書くことで最初の問題を解決しました:

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:私の残念なことにiterateWhile、モナドではこれを正確に行います:)

4

1 に答える 1

1

IORefあなたの場合はやり過ぎです。これは、数行のコードで解決できます。

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可変参照 (関数型プログラミングが回避しようとしている) を表し、非常に慎重に使用する必要があります。最初に純粋な関数を作成して問題を解決することは、常に良い考えです。

于 2015-05-31T18:05:45.123 に答える