Scala中的匿名递归函数

aio*_*obe 43 recursion scala anonymous-function

有没有办法在Scala中编写一个递归的匿名函数?我在考虑这样的事情:

((t: Tree) => {
    print(t.value);
    for (c <- t.children)
        thisMethod(c)
})(root)
Run Code Online (Sandbox Code Playgroud)

(相关问题:哪些语言支持*递归*函数文字/匿名函数?)

小智 50

如您发布的链接中所述.你可以使用Y-combinator.这是一个例子:

scala> def fix[A,B](f: (A=>B)=>(A=>B)): A=>B = f(fix(f))(_)
fix: [A,B](f: ((A) => B) => (A) => B)(A) => B

scala> val fact = fix[Int,Int](f => a => if(a<=0) 1 else f(a-1) * a)
fact: (Int) => Int = <function1>

scala> fact(12)
res0: Int = 479001600
Run Code Online (Sandbox Code Playgroud)

请注意,它不适用于大数字.小心尾调用优化.

  • 原始意义上的"惊人"让我觉得自己迷失在迷宫中.`fix`是一个函数,它接受一个函数,它本身接受一个参数并返回另一个接受一个参数的函数,然后它......好吧,我需要更好的解释来自*某人*.. . (10认同)
  • @Malvolio:`fix`是一个函数,它接受另一个函数`f`作为它的参数,并为该函数返回一个_fixed point_,即一个值`x`,其中`f(x)== x`.计算其他函数的固定点的函数称为[定点组合子](http://en.wikipedia.org/wiki/Fixed_point_combinator).Y组合器只是定点组合器的一个例子.定点组合器提供了一种描述语法中递归的方法,例如lambda演算,它不允许自引用定义. (6认同)

Spa*_*aer 23

如果你不想点击"惊人的数学",你可以回到scala的对象方面.

val fact = new Function1[Int,Int]{
    def apply(x:Int):Int = if(x==1) x else x * apply(x-1)
}
Run Code Online (Sandbox Code Playgroud)


小智 12

为了使它看起来更怪,你也可以使用这种代码风格:

val fact = new ((Int) => Int){
  def apply(x:Int):Int = if(x==1) x else x * apply(x-1)
}
Run Code Online (Sandbox Code Playgroud)


In-*_* Yi 5

在这个线程中添加了许多好的响应,Scala没有给我们尾调用优化定点组合器这一事实一直困扰着我,所以我决定编写一个宏来翻译类似Y-combinator的调用一个普通的,惯用的递归调用(当然,尾部调用优化).这个想法就像是一个电话

fix[Int,Int]((next) => (y) => ...body...)
Run Code Online (Sandbox Code Playgroud)

很容易翻译成

({(input) =>
  object next {
    def apply(y:Int):Int = ...body...
  }
  next(input)
})
Run Code Online (Sandbox Code Playgroud)

我已经将针对Scala 2.11的宏实现(稍微调整也应该与2.10一起使用)放到了这个要点中.

使用这个宏,我们可以匿名方式执行普通的递归任务,而不用担心堆栈溢出,例如

import asia.blip.ymacro.YMacro._
(y[BigInt,BigInt]((xx) => (y) => if(y==1) 1 else y * xx(y-1)))(2000)
Run Code Online (Sandbox Code Playgroud)

res0: BigInt = 33162750924506332411753933805763240382811...
Run Code Online (Sandbox Code Playgroud)