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



我正在查看 scala 中的柯里技术示例,不明白当函数递归时,函数如何返回另一个函数。

例如,我理解此代码

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))

上面的一个对我来说没问题,如果我说中继器(addOne,10,1)返回11。直到 n 等于零,我用 1 减少 n,递归堆栈开始自下而上工作。

但是这个让我感到困惑

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) 再次执行中继器并返回另一个函数? 这 else 部分返回多少个函数,调用堆栈会是什么样子?

让我们一步一步地展开递归。

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))
}

首先,让我们澄清一下,如果你运行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.因此,我们可以仅用myFunc(x)替换整个{ x => 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的返回函数,并放入一个名为fval

val f = { x => addOne(addOne(addOne(x))) } //ie repeater(addOne, 3)

f接受整数输入并返回该整数加 3。然后,我们可以使用它获得我们想要的实际结果

val someIntegerPlus3: Int = f(someInteger)

为了使它更容易理解,我将简化和脱糖您的功能的某些部分。

让我们首先删除myFunc参数并将其替换为直接降低复杂性addOne函数,以保持主要问题:

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

现在让我们来解释一下脱糖函数文字实例化代码

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(...)

最新更新