scala尾递归装饰器不允许调用尾递归函数
scala tail recursion decorator not letting tail recursive function to be called
object FuncUtils {
@tailrec
def tryAll[T](funcs: (() => Any)*): Option[Any] = {
if (funcs.isEmpty) {
None
} else {
try {
Some(funcs.head())
} catch {
case _: Throwable => FuncUtils.tryAll(funcs.tail: _*)
}
}
}
}
为什么?在我看来,tryAll 是自包含的,迭代可以在不引用调用堆栈的情况下发生。
好的原因是因为我在调用函数之前指的是包含该方法的单例对象。
FuncUtils.tryAll(funcs.tail: _*)
应该只是:
tryAll(funcs.tail: _*)
我猜当我引用库时,scala 无法弄清楚它是递归的。
错误不可重现,您可以尝试提供更多上下文。
无论如何,我还建议您避免 Seq
用于 tail-recursive 算法 (您应该改用 List
),并且try / catch
块 (改用 Try
Monad).
这是使用它重写您的代码。
import scala.util.{Try, Success, Failure}
object FuncUtils {
def tryAll[T](funcs: (() => T)*): Option[T] = {
@annotation.tailrec
def loop(remaining: List[() => T]): Option[T] = remaining match {
case Nil => None
case x :: xs => Try(x()) match {
case Success(t) => Some(t)
case Failure(_) => loop(remaining = xs)
}
}
loop(remaining = funcs.toList)
}
}
同样,正如 jwvh 所说,在这种情况下你真的不需要递归。
object FuncUtils {
def tryAll[T](funcs: (() => T)*): Option[T] =
funcs.iterator.map(f => Try(f())).collectFirst { case Success(t) => t }
}
object FuncUtils {
@tailrec
def tryAll[T](funcs: (() => Any)*): Option[Any] = {
if (funcs.isEmpty) {
None
} else {
try {
Some(funcs.head())
} catch {
case _: Throwable => FuncUtils.tryAll(funcs.tail: _*)
}
}
}
}
为什么?在我看来,tryAll 是自包含的,迭代可以在不引用调用堆栈的情况下发生。
好的原因是因为我在调用函数之前指的是包含该方法的单例对象。
FuncUtils.tryAll(funcs.tail: _*)
应该只是:
tryAll(funcs.tail: _*)
我猜当我引用库时,scala 无法弄清楚它是递归的。
错误不可重现,您可以尝试提供更多上下文。
无论如何,我还建议您避免 Seq
用于 tail-recursive 算法 (您应该改用 List
),并且try / catch
块 (改用 Try
Monad).
这是使用它重写您的代码。
import scala.util.{Try, Success, Failure}
object FuncUtils {
def tryAll[T](funcs: (() => T)*): Option[T] = {
@annotation.tailrec
def loop(remaining: List[() => T]): Option[T] = remaining match {
case Nil => None
case x :: xs => Try(x()) match {
case Success(t) => Some(t)
case Failure(_) => loop(remaining = xs)
}
}
loop(remaining = funcs.toList)
}
}
同样,正如 jwvh 所说,在这种情况下你真的不需要递归。
object FuncUtils {
def tryAll[T](funcs: (() => T)*): Option[T] =
funcs.iterator.map(f => Try(f())).collectFirst { case Success(t) => t }
}