我试图使返回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] = ???
简单的回答是:别担心。
cats构建和执行的方式 IO 实例,尤其是 flatMap 非常安全, as described here .
IO
flatMap
当你这样做的时候 x.flatMap(f) , f 不会在同一堆栈中立即执行。它稍后由cats以本质上在内部实现尾部递归的方式执行。作为一个简化的示例,您可以尝试运行:
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 很好。
10000000