代码之家  ›  专栏  ›  技术社区  ›  Jose H. Martinez

Cats IO-在flatmap内进行尾部递归调用

  •  2
  • Jose H. Martinez  · 技术社区  · 7 年前

    我试图使返回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] = ???
    
    1 回复  |  直到 7 年前
        1
  •  3
  •   Pavel Joe K    6 年前

    简单的回答是:别担心。

    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 很好。