Scala 何时对递归函数/方法使用辅助递归函数/方法

Scala 何时对递归函数/方法使用辅助递归函数/方法,scala,recursion,Scala,Recursion,在函数式编程课程的工作表中,我被要求用Scala编写一个函数(尽管我认为教授可能指的是方法),该函数递归地将列表中的元素打印到新行上,并带有行号,结果如下: scala> printCounter (List ("the", "rain", "in", "spain")) [001] the [002] rain [003] in [004] spain def printCounterAux [X] (xs:List[X], count:Int) : Unit = { xs

在函数式编程课程的工作表中,我被要求用Scala编写一个函数(尽管我认为教授可能指的是方法),该函数递归地将列表中的元素打印到新行上,并带有行号,结果如下:

    scala> printCounter (List ("the", "rain", "in", "spain"))
[001] the
[002] rain
[003] in
[004] spain
def printCounterAux [X] (xs:List[X], count:Int) : Unit = {
  xs match {
    case Nil   => ()
    case y::ys => {
      println ("[%03d] %s".format (count, y))
      printCounterAux (ys, count + 1)
    }
  }
}

def printCounter [X] (xs:List[X]) : Unit = {
  printCounterAux (xs, 1)
}

printCounter (List ("the", "rain", "in", "spain"))
工作表上提供的解决方案如下所示:

    scala> printCounter (List ("the", "rain", "in", "spain"))
[001] the
[002] rain
[003] in
[004] spain
def printCounterAux [X] (xs:List[X], count:Int) : Unit = {
  xs match {
    case Nil   => ()
    case y::ys => {
      println ("[%03d] %s".format (count, y))
      printCounterAux (ys, count + 1)
    }
  }
}

def printCounter [X] (xs:List[X]) : Unit = {
  printCounterAux (xs, 1)
}

printCounter (List ("the", "rain", "in", "spain"))

我没有想到要创建一个辅助方法。我的问题是,作为一个仍在掌握递归的人,如何知道何时需要创建一个辅助递归方法?在这种情况下,信号会是多个参数吗?或者仅仅是大量接触这些方法的问题?非常感谢您提供的任何建议。干杯。

打印计数器
的API与
打印计数器
不同。不仅如此,API中的更改与方法的功能无关,它只是一个实现细节。(例如,如果
printCounter
是通过循环实现的,那么就没有必要了。)

因此,您希望对使用者隐藏此API

为了真正正确地隐藏此API,
printCounterAux
应该是
printCounter
的内部函数,如下所示:

def打印计数器[X](xs:List[X]):单位={
打印计数器()
def printCounterAux[X](xs:List[X]=xs,count:Int=1):单位=xs匹配{
案例Nil=>()
案例y::ys=>{
println(“[%03d]%s.”格式(计数,y))
打印计数器(Y,计数+1)
}
}
}
打印计数器(列表(“the”、“rain”、“in”、“spain”))

请注意,在许多情况下,您需要随身携带某种“状态”,在纯函数语言中的递归函数中,携带该状态的一个非常方便的位置是函数的参数。因此,您通常必须修改参数列表,以便添加状态参数(如本例中的计数),该参数不应向使用者公开。

在Scala中,写入是很常见的 身体的局部功能 另一个功能。在功能上 编程,我们不应该考虑 这比局部整数更重要 或字符串

我们在函数上编写循环的方式,不改变循环变量,是递归的 功能。在这里,我们在 阶乘函数。这种辅助函数通常按约定称为go或loop

def factorial(n: Int): Int = {
    def go(n: Int, acc: Int): Int =
        if (n <= 0) acc
        else go(n - 1, n * acc)
    go(n, 1)
}

这是编写内部函数或本地定义的常见场景。

请注意,您可以使用单个参数调用
printCounter(myList)
,但在本例中,
printcountaux
是使用
myList
和数字
1
调用的。这很好,因为函数的调用方不必记住每次都将
1
作为第二个参数发送。您不需要辅助函数,但如果没有,调用方将需要提供初始的
1
。一般来说,当循环的参数与调用站点期望的参数不同时,使用辅助函数。实际上,该辅助函数应该在主函数中声明,这样它实际上是外部世界的私有函数。回答您的问题,您的主(公共)函数不应该公开内部细节,如行号,它应该只接收必须接收的内容并返回必须返回的内容,但是对于实现,您可能需要一些额外的参数来保持状态,因此您创建了一个新的aux函数,仅用于内部使用,你的main函数调用函数具有正确的初始值。基本上,每次你想创建一个(尾部)递归函数时,你都会这样做。在许多情况下,这可以消除对辅助函数的需要,但请注意,调用方可以覆盖调用站点的默认值。例如,您可以编写
def printCounter[X](xs:List[X],count:Int=1):Unit={…}
,当您调用
printCounter(myList)
时,
count
将默认为
1
。但是,如果调用
printCounter(myList,10)
count
将从
10
开始,您将得到一个有点意外的结果。我在函数式编程的上下文中讨论了递归的主题。我想你可能会发现它们很有帮助