นี่คือชิ้นส่วนของรหัสจากเอกสารสำหรับFS2 ฟังก์ชั่นgo
ซ้ำ คำถามคือเราจะรู้ได้อย่างไรว่าปลอดภัยสำหรับสแต็กและวิธีการใช้ฟังก์ชันใดที่ปลอดภัยสแต็ก
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)
มันจะปลอดภัยหรือไม่หากเราเรียกgo
ใช้วิธีอื่น
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
เพื่อใช้เช่นMonad[F]
typeclass - มีtailRecM
วิธีการที่อนุญาตให้คุณใช้แทรมโพลีนอย่างชัดเจนเพื่อรับประกันว่าฟังก์ชั่นนั้นจะปลอดภัย ฉันอาจจะผิด แต่ถ้าไม่มีคุณพึ่งพาF
ความปลอดภัยด้วยตัวเอง (เช่นถ้าใช้แทรมโพลีนภายใน) แต่คุณไม่มีทางรู้เลยว่าใครจะเป็นผู้กำหนดคุณF
ดังนั้นคุณไม่ควรทำเช่นนี้ หากคุณไม่มีการรับประกันว่าF
ปลอดภัยสแต็กให้ใช้คลาสประเภทที่ให้ไว้tailRecM
เพราะมันปลอดภัยสแต็คตามกฎหมาย
@tailrec
คำอธิบายประกอบสำหรับฟังก์ชั่น tail rec สำหรับกรณีอื่น ๆ ไม่มีการรับประกันอย่างเป็นทางการใน Scala AFAIK แม้ว่าฟังก์ชั่นของตัวเองจะปลอดภัย แต่ฟังก์ชั่นอื่น ๆ ที่ใช้อยู่อาจจะไม่: /