gpt4 book ai didi

Scala:蹦床函数的扩展语法破坏了尾递归

转载 作者:行者123 更新时间:2023-12-01 03:01:59 25 4
gpt4 key购买 nike

这是“Scala 中的函数式编程”第 13 章中的一个练习,用于实现用于解释尾递归函数的蹦床。

runTrampoline2 不是尾递归的,并且我的测试输入会溢出堆栈。此外,tailrec 注释给出了 runTrampoline2 的编译器错误。 runTrampoline 是尾递归的并通过了注释的编译时检查。

我认为这两个 trampoline 之间的区别在于 val 捕获或不捕获 Unit 的方式,如下所示:

scala> val foo = println("abc")
val foo = println("abc")
abc
foo: Unit = ()

scala> foo
foo

scala> val bar: Int = {println("xyz"); 5}
val bar: Int = {println("xyz"); 5}
xyz
bar: Int = 5

scala> bar
bar
res8: Int = 5

否则这两个蹦床在我看来是一样的。如果有人评论说它们对这个问题很重要,我将包括 Free monad 和 Suspend、Return 和 FlatMap 构造函数的代码,但我认为它们不是。 runTrampoline2 的尾递归是否被从 val 中泄漏出来的副作用破坏了?谢谢!

@annotation.tailrec
def runTrampoline[A](tra: Free[Function0,A]): A =
tra match {
// case Return(A)
case Return(a1) => a1
// case Suspend(Function0[A])
case Suspend(function0A1) => function0A1()
// case FlatMap(Free[Function0[_],A], A=>Free[Function0,B]]
case FlatMap(free1, aFree2) => free1 match {
// case Return(A)
case Return(a2) => runTrampoline(aFree2(a2))
// case Suspend(Function0[A])
case Suspend(function0A) => runTrampoline(aFree2(function0A()))
// case FlatMap(Free[Function0[_],A], A=>Free[Function0,B]]
case FlatMap(a0,g) =>
runTrampoline {
a0 flatMap { a0 => g(a0) flatMap aFree2 }
}
}
}


//@annotation.tailrec
def runTrampoline2[A](tra: Free[Function0,A]): A =
tra match {
// case Return(A)
case Return(a1) => a1
// case Suspend(Function0[A])
case Suspend(function0A1) => {
val a1: A = function0A1()
a1
}
// case FlatMap(Free[Function0[_],A], A=>Free[Function0,A]]
case FlatMap(free1, aFree2) => free1 match {
// case Return(A)
case Return(a2) => {
val free2: Free[Function0,A] = aFree2(a2)
val a3: A = runTrampoline2(free2)
a3
}
// case Suspend(Function0[A])
case Suspend(function0A) => {
val a2: A = function0A()
val free2: Free[Function0,A] = aFree2(a2)
val a3: A = runTrampoline2(free2)
a3
}
// case FlatMap(Free[Function0[_],A], A=>Free[Function0,B]]
case FlatMap(a0,g) =>
runTrampoline2 {
a0 flatMap { a0 => g(a0) flatMap aFree2 }
}
}
}

一个月前我问过一个类似的问题,关于类型注释破坏尾递归:Scala: type annotations make tail recursion check fail


由 Aivean 解决。这是蹦床的更正版本。每个递归调用都在包含它的案例的最后。

@annotation.tailrec
def runTrampoline3[A](tra: Free[Function0,A]): A =
tra match {
case Return(a1) => a1
case Suspend(function0A1) => {
val a1 = function0A1()
a1
}
case FlatMap(free1, aFree2) => free1 match {
case Return(a2) => {
val free2 = aFree2(a2)
runTrampoline3(free2)
}
case Suspend(function0A) => {
val a2 = function0A()
val free2 = aFree2(a2)
runTrampoline3(free2)
}
case FlatMap(a0,g) =>
runTrampoline3 {
a0 flatMap { a0 => g(a0) flatMap aFree2 }
}
}
}

最佳答案

看起来 Scala 编译器只有在对自身的调用实际上是函数中的最后一个操作时才识别尾递归。

我反编译了两个不同的例子来检查这一点。

尾递归:

斯卡拉:

def rec:Int = rec

Java:

public final class _$$anon$1 {
private int rec() {
while (true) {}
}
}

无尾递归:

斯卡拉:

def rec:Int = {
val i = rec
i
}

Java:

public final class _$$anon$1 {
private int rec() {
final int i = this.rec();
return i;
}
}

关于Scala:蹦床函数的扩展语法破坏了尾递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31622000/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com