可以使尾递归吗?

Can This Be Made Tail Recursive?

我正在访问一个 return 分页 JSON 响应的 HTTP 端点。 'meta.next' 的价值 在我的响应类型中指向响应的下一页。当这个值为null时,没有更多的页面 检索。 我正在使用 Spray IO 发出 HTTP 请求。我收集了每个感兴趣的条目 页面响应并将其与到目前为止收集的内容连接起来。当下一个变成 null,我return所有收集的条目。 我的问题:有没有办法让尾递归下面的 'getJson(...)' 函数?

 case class JsonResponse(meta: Meta, items: List[Item])

 val pipeline: Future[HttpRequest => Future[JsonResponse]] = for (
    Http.HostConnectorInfo(connector, _) <-
    IO(Http) ? Http.HostConnectorSetup("somehost.com", port = 80)
  ) yield sendReceive(connector) ~> unmarshal[JsonResponse]


  // .....

  def getJson(relativeUrl: String)(implicit m: Monoid[Future[List[JsObject]]]) : Future[List[JsObject]] = {

    val jsr = pipeline.flatMap(_(Get(relativeUrl)))

    // Grab only those entries that we are interested in
    val objList = jsr.map(js => js.items.collect{ case o if(o.whatever.isDefined) => o.toJson.asJsObject })

    jsr.flatMap(js => js.meta.next.map(next => m.append(getJson(next), objList)).getOrElse(objList))
  }

尾递归在这里并不适用。当您使用未来的组合器时,您不是在单个堆栈上操作。

具体来说,在每种情况下 getJson 立即 returns。通过使用 jsr.flatMap,您正在注册一个回调,只有在收到 HTTP 请求的响应时才会调用该回调。因此,getJson 的下一次调用也将在此上下文中发生,即在隐式执行上下文提供的回调堆栈上。

因此,虽然递归仍在算法级别上发生,但它不会导致在一个(或任何)线程的堆栈上添加堆栈帧。

关于炸毁堆栈,您的代码很好。您想使用尾递归还有其他原因吗?