Cats IO - 在平面图中进行尾递归调用
Cats IO - Make tail recursive call inside flatmap
我正在尝试使我的函数 returns 成为一个 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.
当您执行 x.flatMap(f)
时,f
不会立即在同一个堆栈中执行。它稍后由 cats 以一种本质上在内部实现尾递归的方式执行。作为一个简化的例子,你可以尝试 运行:
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
就好了。
我正在尝试使我的函数 returns 成为一个 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.
当您执行 x.flatMap(f)
时,f
不会立即在同一个堆栈中执行。它稍后由 cats 以一种本质上在内部实现尾递归的方式执行。作为一个简化的例子,你可以尝试 运行:
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
就好了。