Berikut adalah sepotong kode dari dokumentasi untuk fs2 . Fungsi goini bersifat rekursif. Pertanyaannya adalah bagaimana kita tahu apakah itu stack safe dan bagaimana alasannya jika ada fungsi stack safe?
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)
Apakah ini juga akan menjadi tumpukan aman jika kita memanggil godari metode lain?
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
}
gountuk menggunakan mis. Monad[F]Typeclass - ada tailRecMmetode yang memungkinkan Anda untuk melakukan trampolin secara eksplisit untuk menjamin bahwa fungsi tersebut akan menjadi stack safe. Saya mungkin salah tetapi tanpa itu Anda mengandalkan Ftumpukan aman sendiri (misalnya jika itu menerapkan trampolin secara internal), tetapi Anda tidak pernah tahu siapa yang akan menentukan Anda F, jadi Anda tidak harus melakukan ini. Jika Anda tidak memiliki jaminan bahwa itu Fadalah stack safe, gunakan kelas tipe yang menyediakan tailRecMkarena itu adalah stack-safe oleh hukum.
@tailrecanotasi untuk fungsi tail rec. Untuk kasus lain tidak ada jaminan formal di Scala AFAIK. Bahkan jika fungsi itu sendiri aman, fungsi lain yang dihubungi mungkin tidak: /.