【问题标题】:Understanding how to convert recursive to a trampoline了解如何将递归转换为蹦床
【发布时间】:2014-04-03 00:13:10
【问题描述】:

我最近读到关于蹦床作为一种消除尾声的方法。我想将我的一个功能转换为利用蹦床的功能,但我很难开始(我来自 OO 世界)。

def buildTree (X:DenseMatrix[Double], Y:DenseVector[Double], minBucket:Int):Node = {
        // Get the split variable, split point and data for this data
        val (splitVar, splitPoint, leftX, leftY, rightX, rightY) = chooseSplit(X, Y, minBucket);
        // If we couldn't find a split, then we have a leaf
        if(splitVar == Double.NegativeInfinity){
            new Node(Y)
        }else{
            // Otherwise recursively build the children and create yourself as a vertex
            val left =  buildTree(leftX, leftY, minBucket))
            val right = buildTree(rightX, rightY, minBucket))
            new Node(Y, splitVar, splitPoint, left, right)
        }
    }

具体来说,如果我想在“More()”语句中进行两个不同的递归调用,可以吗?

【问题讨论】:

    标签: scala recursion tail-recursion trampolines


    【解决方案1】:

    您的buildTree 方法不会进行任何尾调用,因此无法利用蹦床。当一个方法的返回值是另一个方法调用的结果时,尾调用是一种优化。它允许将堆栈帧替换为被调用函数的堆栈帧。如果没有尾调用优化,递归函数调用会导致堆栈增大,可能导致堆栈溢出。您的 buildTree 方法确实会调用自己两次,但必须保留原始堆栈框架,以便可以将两个函数调用的结果组合起来创建新的 Node

    JVM 没有内置支持 tail all 优化,但 Scala 对函数调用自身的尾部调用有一个技巧。 Scala 将这些递归函数调用替换为跳转到函数的开头,从而有效地将递归转换为迭代。不幸的是,这不适用于协同递归调用(例如,当方法 A 调用 B 而调用 A 时)。 Trampolining 可以在这里使用,或者基于特殊的 monad,或者滥用异常处理。没有理由在其他地方使用蹦床。

    【讨论】:

      猜你喜欢
      • 2021-06-01
      • 1970-01-01
      • 2018-11-02
      • 2016-03-24
      • 1970-01-01
      • 1970-01-01
      • 2014-10-03
      • 1970-01-01
      • 2018-11-27
      相关资源
      最近更新 更多