Scala 谓词保持时重复调用函数

Scala 谓词保持时重复调用函数,scala,functional-programming,Scala,Functional Programming,我正在向远程服务器发出请求,有时请求会因为网络不可靠而失败。如果失败,我希望请求重复,但最多重复n次。如果我使用命令式语言,我会将请求发送代码放在while循环中,但我希望以功能性的方式执行 为此,我已编写了帮助程序: /** Repeatedly executes function `f` * while predicate `p` holds * but no more than `nTries` times. */ def repeatWhile[A](f: => A)

我正在向远程服务器发出请求,有时请求会因为网络不可靠而失败。如果失败,我希望请求重复,但最多重复
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)
我的
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)

规范的方法是使用:

这将为您提供一个空列表或一个项目列表,具体取决于它是否成功。如果您愿意,可以将其转换为带有
headOption
的选项。只要稍作修改,它就可以在所有用例上工作


像您这样编写小型递归方法也是非常明智的,尽管它们不在库中。一般来说,为您最常做的事情编写助手方法是一个非常好的主意。这就是Scala使编写方法变得如此简单的原因之一。

谢谢!它可以写得更短,如
迭代器。连续(f)。获取(nTries)。查找(p)
。是否可以使用
而不是
迭代器
?有什么区别?@lpaul7 Stream将始终计算当前元素。仅仅创建它就会导致它调用函数一次。@lpaul7
Stream.fill(nTries)(f).find(p)
甚至更短!我更喜欢流,因为它们是不可变的@Kaito,在这种情况下这并不重要,因为我们至少要立即评估头部。如果您不想急切地评估头部,您可以将
分配给
惰性val
@luigipling True,在这种情况下这并不重要,但这是一个区别,在其他情况下可能很重要。使用惰性val只能工作一次。执行
Stream:drop(1)
仍将导致它计算2项,而
Iterator:drop(1)
将只计算1项。(可以说这两种情况下都不应该计算任何东西)
/** 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)
Iterator.continually{f}.take(nTries).dropWhile(!p).take(1).toList