Đây là một đoạn mã từ tài liệu cho fs2 . Hàm gođược đệ quy. Câu hỏi là làm thế nào để chúng ta biết nếu nó là stack an toàn và làm thế nào để suy luận nếu bất kỳ chức năng nào là stack an toàn?
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)
Nó cũng sẽ được ngăn xếp an toàn nếu chúng ta gọi gotừ một phương thức khác?
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để sử dụng ví dụ như Monad[F]typeclass - có tailRecMphương pháp cho phép bạn thực hiện trampoline một cách rõ ràng để đảm bảo rằng chức năng sẽ được xếp chồng an toàn. Tôi có thể sai nhưng không có nó, bạn đang dựa vào Fviệc tự mình xếp chồng an toàn (ví dụ: nếu nó thực hiện trampoline trong nội bộ), nhưng bạn không bao giờ biết ai sẽ xác định bạn F, vì vậy bạn không nên làm điều này. Nếu bạn không có gì đảm bảo rằng Fstack an toàn, hãy sử dụng một loại lớp cung cấp tailRecMbởi vì nó là stack an toàn theo luật.
@tailrecchú thích cho các hàm rec đuôi. Đối với các trường hợp khác, không có đảm bảo chính thức trong Scala AFAIK. Ngay cả khi chức năng đó an toàn, các chức năng khác mà nó gọi có thể không phải là: /.