猫IO-在Flatmap中进行尾部递归呼叫



我正在尝试使我的功能返回io尾部递归,但由于我在flatmap中使用了它,因此不会编译它。我知道有一些目的是为此目的而建立的,例如TailRec,但我正在寻找有关如何使用它们的指导。这是示例代码。

    import cats.effect.IO
    import scala.annotation.tailrec
    def process(since: Option[String]): IO[Seq[String]] = {
      @tailrec
      def go(startIndex: Int): IO[(Int, Seq[String])] = {
        val program = since match {
          case Some(s) =>
            for {
              r <- fetchResponse(s, startIndex)
              size = r.size
              ss = r.data
              _ <- writeResponse(ss)
            } yield (size,  r)
          case None => IO((0, Seq.empty[String]))
        }
        program.flatMap { case (size, _) =>
          if (startIndex <= size) go( startIndex + size)
          else IO((0, Seq.empty))
        }
      }
      go(0).map(o => o._2)
    }
    case class Response(size: Int, data: Seq[String])
    def fetchResponse(s: String, i: Int): IO[Response] = ???
    def writeResponse(r: Seq[String]): IO[Int] = ???

简短的答案是:不用担心。

猫构建和执行IO实例的方式,尤其是使用flatMap是非常堆栈的安全,如下所述。

执行x.flatMap(f)时,f不会在同一堆栈中立即执行。猫后来以一种基本上在内部实现尾部递归的方式执行。作为简化的示例,您可以尝试运行:

def calculate(start: Int, end: Int): IO[Int] = {
  IO(start).flatMap { x =>
    if (x == end) IO(x) else calculate(start + 1, end)
  }
}
calculate(0, 10000000).flatMap(x => IO(println(x))).unsafeRunSync()

本质上与您的工作完全相同,并且可以打印出10000000

最新更新