【问题标题】:Cats IO - Make tail recursive call inside flatmapCats IO - 在平面图中进行尾递归调用
【发布时间】:2019-04-24 02:25:58
【问题描述】:

我正在尝试使我的函数返回一个 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] = ???

【问题讨论】:

  • 整个结构的哪一部分应该是尾递归的?你打算对val 上的@tailrec 注释做什么?
  • 道歉。 Go应该是递归的。修复代码

标签: scala scala-cats


【解决方案1】:

简短的回答是:别担心。

猫构造和执行IO 实例的方式,尤其是flatMap,是非常堆栈安全的,as described here

当您执行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 就好了。

【讨论】:

  • 这似乎在我身上死了:def f(x: Int): IO[Int] = IO.whenA (x % 1234 == 0) { IO(println(x)) } *&gt; (if (x != 0) (f(x - 1)) else IO(0)) for f(100000).unsafeRunSync()。有什么不同吗?
猜你喜欢
  • 1970-01-01
  • 2021-06-29
  • 1970-01-01
  • 2016-03-21
  • 1970-01-01
  • 2021-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多