对函数的循环调用,直到它返回None

Cal*_*oiu 9 functional-programming scala

我经常遇到一个模式,所以我想知道Scala库中是否有任何方便的方法.

让它成为一种功能f: A => Option[B].我愿做一个反复调用f一个起点开始x,f(f(f(x).get).get...)直至f恢复None并保持最后的非None价值.

我为此写了一个实现:

@tailrec
def recurrentCallUntilNone[B](f: B => Option[B], x: B): B = f(x) match {
  case Some(y) => recurrentCallUntilNone(f, y)
  case None => x
}
Run Code Online (Sandbox Code Playgroud)

这已经在标准库中实现了吗?

对此的使用示例可以是用于保持当前位置的列表(Zipper).通过调用next,None如果在当前位置之后没有元素或者Option对于相同列表没有元素但是当前位置递增,则返回.通过使用上述方法,end可以构造一种寻找列表到最后的方法.

iai*_*ain 2

你正在做的事情看起来像是一种非常特殊类型的蹦床。更一般的情况使用包装在案例类中的函数而不是 anOption并支持不同的参数和返回类型。

正如 Calin-Andrei 指出的那样,标准库中可以使用TailCalls 对象来使用蹦床。

从第一个链接:

def even2(n: Int): Bounce[Boolean] = {
  if (n == 0) Done(true)
  else Call(() => odd2(n - 1))
}
def odd2(n: Int): Bounce[Boolean] = {
  if (n == 0) Done(false)
  else Call(() => even2(n - 1))
}
trampoline(even2(9999))

sealed trait Bounce[A]
case class Done[A](result: A) extends Bounce[A]
case class Call[A](thunk: () => Bounce[A]) extends Bounce[A]

def trampoline[A](bounce: Bounce[A]): A = bounce match {
  case Call(thunk) => trampoline(thunk())
  case Done(x) => x
}
Run Code Online (Sandbox Code Playgroud)

现在有了标准库

import scala.util.control.TailCalls._

def even2(n: Int): TailRec[Boolean] = {
  if (n == 0) done(true)
  else tailcall(odd2(n - 1))
}
def odd2(n: Int): TailRec[Boolean] = {
  if (n == 0) done(false)
  else tailcall(even2(n - 1))
}
even2(9999).result
Run Code Online (Sandbox Code Playgroud)