【问题标题】:could not optimize @tailrec annotated method loop: it contains a recursive call not in tail position无法优化 @tailrec 带注释的方法循环:它包含一个不在尾部位置的递归调用
【发布时间】:2015-10-28 00:22:54
【问题描述】:

我有以下递归函数,我想对其使用尾递归。但是编译器用这个错误抱怨我的实现:Error:(79, 7) could not optimize @tailrec annotated method loop: it contains a recursive call not in tail position n match { ^

是不是因为for循环它假设它不在尾部位置?

def dsl[N,E](qNodes:QNodeLike[N,E]*) = {
    val markers = scala.collection.mutable.Map.empty[String, N]
    @tailrec
    def loop(n:QNodeLike[N,E]):Unit = {
      n match {
        case QNode(head, kids:Seq[HalfEdgeLike[E,N]]) => {

          for(kid <- kids){
            kid match {
              case EmptyHalfEdge() =>
              case HalfEdge(e, n) => loop(n)
            }
          }
        }

        case QNodeMarker(head, marker, kids:Seq[HalfEdgeLike[E,N]]) => {
          markers.update(marker,head)
          for(kid <- kids){
            kid match {
              case EmptyHalfEdge() =>
              case HalfEdge(e, n) => loop(n)
            }
          }
        }
      }
    }

    loop(qNodes.head)
  }

【问题讨论】:

    标签: scala recursion tail-recursion


    【解决方案1】:

    是的,没错。为了让它尾递归,你应该使用一个显式的累加器,它被传递到递归中。

    但是,除非您有 非常 深且窄的树,否则您不太可能需要尾递归优化,因为在您最终导致堆栈溢出之前,运行时间会变得非常长。 p>

    以下是如何使其尾部优化的粗略想法:

    @tailrec
    def loop(n:List[QNodeLike[N,E]]):Unit = {
      n match {
        case QNode(head, kids:Seq[HalfEdgeLike[E,N]]) :: rem => {
          kids match {
            case Nil =>
            case EmptyHalfEdge() :: rem2 => loop(rem2 ::: rem)
            case HalfEdge(e, n) :: rem2 => loop(n :: rem2 ::: rem)
          }
        }
    
        case QNodeMarker(head, marker, kids:Seq[HalfEdgeLike[E,N]]) :: rem => {
          markers.update(marker,head)
          kids match {
            case Nil =>
            case EmptyHalfEdge() :: rem2 => loop(rem2 ::: rem)
            case HalfEdge(e, n) :: rem2 => loop(n :: rem2 ::: rem)
          }
        }
    
        case Nil =>
      }
    }
    

    【讨论】:

    • 感谢您的回答,但关于您的解决方案:rem2 的类型是 Seq[HaldEdgeLike[N,E]] 而不是 SeqpQNodeLike[N,E]]
    • 啊.. HalfEdgeLike 不是 QNodeLike 的子类型?这让它有点混乱,但你可以应用相同的原则。只需传递两个参数edgeLikeRemnodeLikeRem 并分别处理。
    • 或者,将两级递归展开到一个函数中,以便在一个堆栈帧中提取 QNode 的所有 HalfEdges 中的所有 QNodeLikes,因此只传递 @987654326 @s 在累加器中
    【解决方案2】:

    是的,这是因为循环。 tailrec 函数的结果必须是递归调用的结果。在您的情况下,结果是 for 语句的结果。

    【讨论】:

      猜你喜欢
      • 2015-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-11
      • 2011-09-13
      • 2020-06-26
      • 2021-05-30
      相关资源
      最近更新 更多