Hier ist ein Teil des Codes aus der Dokumentation für fs2 . Die Funktion goist rekursiv. Die Frage ist, woher wissen wir, ob es stapelsicher ist und wie man begründet, ob eine Funktion stapelsicher ist?
import fs2._
// import fs2._
def tk[F[_],O](n: Long): Pipe[F,O,O] = {
def go(s: Stream[F,O], n: Long): Pull[F,O,Unit] = {
s.pull.uncons.flatMap {
case Some((hd,tl)) =>
hd.size match {
case m if m <= n => Pull.output(hd) >> go(tl, n - m)
case m => Pull.output(hd.take(n.toInt)) >> Pull.done
}
case None => Pull.done
}
}
in => go(in,n).stream
}
// tk: [F[_], O](n: Long)fs2.Pipe[F,O,O]
Stream(1,2,3,4).through(tk(2)).toList
// res33: List[Int] = List(1, 2)
Wäre es auch stapelsicher, wenn wir govon einer anderen Methode aus aufrufen ?
def tk[F[_],O](n: Long): Pipe[F,O,O] = {
def go(s: Stream[F,O], n: Long): Pull[F,O,Unit] = {
s.pull.uncons.flatMap {
case Some((hd,tl)) =>
hd.size match {
case m if m <= n => otherMethod(...)
case m => Pull.output(hd.take(n.toInt)) >> Pull.done
}
case None => Pull.done
}
}
def otherMethod(...) = {
Pull.output(hd) >> go(tl, n - m)
}
in => go(in,n).stream
}
go, um z. B. eine Monad[F]Typklasse zu verwenden. Es gibt eine tailRecMMethode, mit der Sie das Trampolin explizit ausführen können, um sicherzustellen, dass die Funktion stapelsicher ist. Ich könnte mich irren, aber ohne sie verlassen Sie sich darauf, Fdass Sie selbst stapelsicher sind (z. B. wenn es Trampolin intern implementiert), aber Sie wissen nie, wer Ihr definiert F, also sollten Sie dies nicht tun. Wenn Sie keine stapelsichere Garantie haben F, verwenden Sie eine Typklasse, die dies vorsieht, tailRecMda sie gesetzlich stapelsicher ist.
@tailrecAnmerkungen für Tail Rec-Funktionen beweisen zu lassen . Für andere Fälle gibt es in der Scala AFAIK keine formellen Garantien. Selbst wenn die Funktion selbst sicher ist, sind die anderen Funktionen, die sie aufruft, möglicherweise nicht: /.