Неоднократно вызывать функцию, пока удерживается предикат

Я отправляю запросы на удаленный сервер, и иногда запросы терпят неудачу из-за ненадежной сети. В случае сбоя я хочу, чтобы запрос повторялся, но 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— глупая функция для целей тестирования. Этот код делает 4 вызова, прежде чем receiveнаконец завершается успешно сSome(Result):

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

Мой repeatWhileработает нормально, но мне хочется заново изобретать велосипед. Я изучаю функциональное программирование и хочу знать, есть ли простые/стандартные решения моей проблемы.

P.S. Я определил еще больше хелперов, возможно, они уже есть в языковой/стандартной библиотеке?

/** 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)
11
задан lambdas 24 September 2012 в 05:18
поделиться