11

リモートサーバーにリクエストを送信していますが、ネットワークの信頼性が低いためにリクエストが失敗することがあります。失敗した場合は、リクエストを繰り返したいのですがn、最大時間です。命令型言語を使用している場合は、リクエスト送信コードをwhileループに配置しますが、関数型の方法で実行したいと思います。

私はこの目的のためにヘルパーを書きました:

/** Repeatedly executes function `f` 
  * while predicate `p` holds
  * but no more than `nTries` times.
  */
def repeatWhile[A](f: => A)(p: A => Boolean)(nTries: Int): Option[A] =
  if (nTries == 0) {
    None
  } else {
    f match {
      case a if p(a) => repeatWhile(f)(p)(nTries - 1)
      case a         => Some(a)
    }
  }

そしてそれをこのように使う:

// Emulating unreliable connection
var n = 0
def receive(): Option[String] =
  if (n < 4) {
    n += 1
    println("No result...")
    None
  } else {
    println("Result!")
    Some("Result")
  }

// Repeated call
val result = repeatWhile(receive)(!_.isDefined)(10)

ここreceiveで、はテスト目的のばかげた関数です。このコードは、receive最終的に成功する前に4回の呼び出しを行いSome(Result)ます。

No result...
No result...
No result...
No result...
Result!

repeatWhileはうまく機能しますが、車輪の再発明をしたいと思っています。私は関数型プログラミングを研究していて、私の問題に対する単純な/標準的な解決策があるかどうか知りたいです。

追伸私はさらに多くのヘルパーを定義しました、多分彼らはすでに言語/標準ライブラリにありますか?

/** Repeatedly executes function `f` 
  * while predicated `p` not holds
  * but no more than `nTries` times.
  */
def repeatWhileNot[A](f: => A)(p: A => Boolean)(nTries:Int): Option[A] = 
  repeatWhile(f)(!p(_))(nTries)

/** Repeatedly executes function `f` 
  * while it returns None 
  * but no more than `nTries` times.
  */
def repeatWhileNone[A](f: => Option[A])(nTries:Int): Option[A] = 
  repeatWhileNot(f)(_.isDefined)(nTries).getOrElse(None)
4

1 に答える 1

16

標準的な方法は、Iterator:を使用することです。

Iterator.continually{f}.take(nTries).dropWhile(!p).take(1).toList

これにより、成功したかどうかに応じて、空のリストまたは1つのアイテムのリストが表示されます。必要に応じて、これをオプションに変換できますheadOption。小さな変更を加えるだけで、これはすべてのユースケースで機能します。

ライブラリにはありませんが、行ったように小さな再帰メソッドを作成することも完全に賢明です。一般に、あなたが最も行うことのためのヘルパーメソッドを書くことは非常に良い考えです。これが、Scalaがメソッドの記述を非常に簡単にする理由の1つです。

于 2012-07-07T18:32:18.387 に答える