Scala 中的匿名递归函数

发布于 2024-10-22 07:41:45 字数 332 浏览 2 评论 0 原文

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

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

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

Is there a way to write an anonymous function that is recursive in Scala? I'm thinking of something like this:

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

(Related question: Which languages support *recursive* function literals / anonymous functions?)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

转身泪倾城 2024-10-29 07:41:45

正如您发布的链接中所述。您可以使用 Y 组合器。这是示例:

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

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

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.

深陷 2024-10-29 07:41:45

如果你不想学习“神奇的数学”,你可以回到 scala 的对象方面。

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

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)
}
旧伤慢歌 2024-10-29 07:41:45

为了使它看起来更极客,您还可以使用以下代码风格:

val fact = new ((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)
}
寒冷纷飞旳雪 2024-10-29 07:41:45

除了本线程中的许多良好响应之外,Scala 没有为我们提供尾部调用可优化定点组合器这一事实一直困扰着我,因此我决定编写一个宏来转换类似 Y 组合器的调用到一个普通的、惯用的递归调用(当然,带有尾调用优化)。这个想法是,像这样的调用

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

很容易翻译成

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

我已经将针对 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)

给出

res0: BigInt = 33162750924506332411753933805763240382811...

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...
凉月流沐 2024-10-29 07:41:45

Scala 上的递归调用。
让我以 N 个数字之和为例进行递归

var sumIt:(Int => Int) = (x: Int) => {if(x<=1) 1 else sumIt(x-1)+x}


 scala> sumIt(10) 
val res141: Int = 55

您可以看到 sumIt 的类型为 Int,Int 作为输入和返回值。 sumIt lambda 函数采用 Integer 作为参数,并对 sumIt 进行递归调用。

我只是为了方便理解递归调用而举这个例子。您可以直接计算此逻辑的公式,例如...

sumValue = (N*(N+1)) /2

Recursive calls on Scala.
Let me take sum of N numbers example for recursion

var sumIt:(Int => Int) = (x: Int) => {if(x<=1) 1 else sumIt(x-1)+x}


 scala> sumIt(10) 
val res141: Int = 55

You can see the sumIt has its type with Int, Int as Input and the return value. The sumIt lambda function takes as argument which is an Integer and it does recursive call on sumIt.

I just this example for easy understanding the recursion call. You can direct formula for this logic like...

sumValue = (N*(N+1)) /2
小苏打饼 2024-10-29 07:41:45

添加到 @in-ho-yi 的答案。为简单起见,您可以直接在匿名函数内部定义本地函数并将其用于递归。另外,在本地函数之前使用 @tailrec 可以确保它将应用尾递归,而 Y 组合器无法做到这一点。

这是比 Y-combinator 更好的方法,因为它只向堆栈添加 2 帧,并且每次调用函数时添加 1 帧(如果不是尾递归,则总共只会添加 1 帧,因此最多将使用 3 帧)而不是 Y-combinator 使用的每次调用 6 个

import scala.annotation.tailrec

val fact = {(input: BigInt)=>
  @tailrec
  def f(x:BigInt, acc: BigInt = 1):BigInt = {
    if(x<=1) acc
    else f(x-1, x*acc)
  }
  f(input)
}

print(fact(1024))

To add onto @in-ho-yi 's answer. For simplicity you can directly define a local function inside of an anonymous function and use it for recursion. Also using @tailrec before the local function you can make sure it will apply tail recursion which you can't do with the Y-combinator.

This is a better approach than Y-combinator because it only adds 2 frames to the stack and 1 per call of the function (if it's not tail recursive, if it is it will only add 1 in total so 3 frames max will be used) instead of 6 per call that Y-combinator uses

import scala.annotation.tailrec

val fact = {(input: BigInt)=>
  @tailrec
  def f(x:BigInt, acc: BigInt = 1):BigInt = {
    if(x<=1) acc
    else f(x-1, x*acc)
  }
  f(input)
}

print(fact(1024))
嘿咻 2024-10-29 07:41:45

一个非常简单的方法:

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)

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文