返回另一个函数的scala递归函数

时间:2019-04-10 12:31:02

标签: scala recursion higher-order-functions currying

我正在看Scala中的currying技术示例,但不了解当函数递归时,函数如何返回另一个函数。

例如,我了解这段代码

def addOne(x: Int): Int = x => x + 1
def repeater(myFunc: Int => Int, n: Int, x:Int): Int = 
    if(n<=0) x
    else repeater(myFunc, n-1, myFunc(x))

对于我来说,上面的一个可以,如果我说Repeater(addOne,10,1)返回11。直到n等于零,我将n减1,递归堆栈开始从下往上工作。

但是这个让我感到困惑

def repeater(myFunc: Int => Int, n:Int): Int => Int = {
   if(n<=0) (x:Int) => x
   else (x: Int) => repeater(myFunc, n-1)(myFunc(x))
}

例如,如果我运行Repeater(addOne,2),我在这里不明白这一点,它将看起来是else部分,而else部分说要返回一个函数,因此程序首先返回一个函数,或者执行n-1(1-1)再转发一次并返回另一个函数? 其他部分返回多少个函数,以及调用堆栈是什么样的?

3 个答案:

答案 0 :(得分:1)

让我们逐步展开递归。

repeater(addOne, 2)返回新的匿名函数

(x:Int) => repeater(addOne, 1).apply(addOne(x))

repeater(addOne, 1)返回新的匿名函数

(x:Int) => repeater(addOne, 0).apply(addOne(x))

repeater(addOne, 0)返回新的匿名函数

(x:Int) => x

因此,repeater(addOne, 1)返回一个类似于

的匿名函数。
(y:Int) => {
    ((x: Int) => {
        x
    }).apply(addOne(y))
}

然后repeater(addOne, 2)返回一个类似于

的匿名函数。
(z:Int) => {
    ((y: Int) => {
        ((x: Int) => {
            x
        }).apply(addOne(y))
    }).apply(addOne(z))
}

答案 1 :(得分:1)

为了使它更容易理解,我将简化并去除功能的某些部分。

让我们首先删除myFunc参数,并用addOne函数替换它,直接降低复杂性,使主要问题集中在焦点上:

def repeater(n:Int): Int => Int = {
   if(n<=0) (x:Int) => x
   else (x: Int) => repeater(n-1)(addOne(x))
}

现在让我们将desugar函数的文字实例化代码

def repeater(n:Int): Int => Int = {
  if(n<=0) new Function1[Int,Int]{ //#1
    override def apply(x: Int): Int = x
  }
  else new Function1[Int,Int]{ //#2
    override def apply(x: Int): Int = repeater(n-1)(addOne(x))
  }
}

因此,现在您可以看到,调用reporter(2)时,它会生成新函数#2而不进行评估。因此,结果将是这样的:

val repeaterFirstIteration: Int => Int = {
  new Function1[Int,Int]{
    override def apply(x: Int): Int = repeater(2-1)(addOne(x))
  }
}

或者我们加糖

val repeaterFirstIteration: Int => Int = {
  x => repeater(2-1)(addOne(x))
}

所以现在您有val包含函数文字,可以像这样repeaterFirstIteration(...)调用

答案 2 :(得分:1)

首先,让我们澄清一下,如果您运行repeater(addOne, 3),则只会获得一个函数。您需要运行repeater(addOne, 3)(SomeOtherInteger)以获取整数值和计算结果。递归在这里所做的所有事情就是构造一个函数。 repeater(addOne, 3)返回一个接受整数并返回整数的函数。以repeater(addOne, 3)为例,如果我们完全写出递归的结果,这就是我们得到的

{ x => {x => { x => { x => x }(myFunc(x)) }(myFunc(x)) }(myFunc(x))) }

它可能看起来有些混乱,但让我们对其进行分解。

让我们专注于最里面的部分-{ x => x }(myFunc(x))。它可以分为两部分,一个函数和该函数的输入。该函数为{ x => x },此函数的输入为(myFunc(x))。在这种情况下,该功能所要做的就是将输入返回给用户。因此,如果我们写{ x => x }(1),我们将得到1。因此我们可以将整个{ x => x }(myFunc(x))替换为myFunc(x)。剩下的就是

  { x => { x => { x => myFunc(x) }(myFunc(x)) }(myFunc(x)) }

让我们看看{ x => myFunc(x)}(myFunc(x))这个词。这里的功能部分是{ x => myFunc(x) },此功能部分的输入由(myFunc(x))给出。函数部分接受一个整数x并将myFunc应用于该整数。本质上与直接将myFunc应用于该整数相同。在这种情况下,我们将其应用于的整数是输入myFunc(x),因此我们可以将{ x => myFunc(x) }(myFunc(x))重写为myFunc(myFunc(x))。现在我们有

   { x => { x => myFunc(myFunc(x)) }(myFunc(x)) }

我们可以应用上一步中使用的相同逻辑来分解{ x => myFunc(myFunc(x)) }(myFunc(x))项。我们将得到myFunc(myFunc(myFunc(x)))。如果继续执行此逻辑,您将看到repeater将继续组成myFunc。对于每个n,它将添加另外一层myFunc。如果n = 3

,结果将如下所示:
   { x  => myFunc(myFunc(myFunc((x))) }

因此repeater(addOne, 3),我们将得到

{ x => addOne(addOne(addOne(x))) }

repeater(addOne, 5)

{ x => addOne(addOne(addOne(addOne(addOne(x))))) }

repeater所做的所有事情只是构造此函数并将其返回给用户。您可以使用repeater的返回函数,然后将其放入名为val的{​​{1}}

f

val f = { x => addOne(addOne(addOne(x))) } //ie repeater(addOne, 3) 接受一个整数输入并返回该整数加3。然后,我们可以使用此数字获得想要的实际结果

f