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

问题描述 投票:0回答:3

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

如果我说转发器(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部分而其他部分则表示返回一个函数,因此程序首先返回一个函数,或者再执行一个转发器时间用n-1(1-1)并返回另一个功能?这个else部分返回了多少函数,调用堆栈会是什么样子?

scala recursion higher-order-functions currying
3个回答
2
投票

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

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

2
投票

首先,让我们澄清一下,如果你运行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的这个返回函数放入一个名为valf

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

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

 val someIntegerPlus3: Int = f(someInteger)

2
投票

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

让我们首先删除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(...)一样调用

© www.soinside.com 2019 - 2024. All rights reserved.