我正在看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)再转发一次并返回另一个函数? 其他部分返回多少个函数,以及调用堆栈是什么样的?
答案 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