다음은 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에는 공식적인 보증이 없습니다. 함수 자체가 안전하더라도 호출하는 다른 함수는 : /가 아닐 수 있습니다.