Anonymous recursive function in Scala

隐身守侯 提交于 2019-11-29 19:57:43
Rustem Suniev

As described in the link you posted. You can use Y-combinator. Here is example:

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

Note it doesn't work with big numbers. Be careful with tail call optimization.

Spangaer

If you don't want to hit the "Amazing mathematics" you could just revert to the object aspects of scala.

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

in order to make it look geekier you can also use this code style:

val fact = new ((Int) => Int){
  def apply(x:Int):Int = if(x==1) x else x * apply(x-1)
}

Adding to the many good responses here in this thread, the fact that Scala is not giving us tail call optimizable Fixed-point combinator has been bothering me so much so that I've decided to write a macro to translate Y-combinator-like call to an ordinary, idiomatic recursive call (with tail call optimization, of course). The idea is that a call like

fix[Int,Int]((next) => (y) => ...body...)

is readily translatable into

({(input) =>
  object next {
    def apply(y:Int):Int = ...body...
  }
  next(input)
})

I've put up macro implementation targeting Scala 2.11 (with minor tweak should also work with 2.10) into this gist.

With this macro, we can perform ordinary recursive tasks in anonymous manner without fearing stack overflow e.g.

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

gives

res0: BigInt = 33162750924506332411753933805763240382811...

A very simple approach:

val fact = { (x: Int) =>
  def f(x: Int): Int = if (x == 0) 1 else x * f(x-1)
  f(x)
}

// Use as anonymous function below
(1 to 5).map { (x: Int) =>
  def f(x: Int): Int = if (x == 0) 1 else x * f(x-1)
  f(x)
}

// res0: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 6, 24, 120)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!