Wenn ich richtig verstehe, kann scala.util.control.TailCalls verwendet werden, um Stapelüberläufe für nicht-tail-rekursive Funktionen zu vermeiden, indem Sie ein Trampolin verwenden. Das Beispiel in der API gegeben ist einfach:Wie benutzt man TailCalls?
import scala.util.control.TailCalls._
def isEven(xs: List[Int]): TailRec[Boolean] =
if (xs.isEmpty) done(true) else tailcall(isOdd(xs.tail))
def isOdd(xs: List[Int]): TailRec[Boolean] =
if (xs.isEmpty) done(false) else tailcall(isEven(xs.tail))
isEven((1 to 100000).toList).result
jedoch umso interessanter Fall ist, wenn Sie einige Operationen nach der recursve Anruf machen wollen. Ich habe eine „naive“ faktorielles Umsetzung irgendwie durch
def fac(n:Long): TailRec[Long] =
if (n == 0) done(1) else done(n * tailcall(fac(n - 1)).result)
läuft, aber das sieht schrecklich und ich bezweifle, dass dies nicht die beabsichtigte Verwendung ist. Also meine Frage ist, wie man eine Fakultät oder Fibonacci-Funktion korrekt mit TailCalls schreiben kann (ja, ich weiß, wie man Akkumulatoren verwendet, um sie tail-rekursiv zu bekommen)? Oder ist TailCalls nicht für diese Art von Problem geeignet?
Wenn Sie sagen "scala.util.control.TailCalls ist ein Hack", können Sie bitte mehr sagen, wann es angebracht ist zu verwenden? –
"hack" war hier nicht pervers gemeint. TailCalls ist perfekt geeignet, um einen Stapelüberlauf von gegenseitig rekursiven Aufrufen zu vermeiden. –