尾递归问题

发布于 2024-12-10 22:09:46 字数 353 浏览 0 评论 0原文

我们正在 Scala 中试验并行集合,并想检查结果是否有序。为此,我在 REPL 上编写了一个小函数来对我们正在生成的非常大的列表进行检查:

def isOrdered(l:List[Int]):Boolean = { l match { 
  case Nil => true
  case x::Nil => true
  case x::y::Nil => x>y
  case x::y::tail => x>y & isOrdered(tail) 
  }
}

它因 stackOverflow 而失败(对于这里的问题来说多么合适!)。 我期待它能进行尾部优化。怎么了?

We were experimenting with parallel collections in Scala and wanted to check whether the result was ordered. For that, I wrote a small function on the REPL to do that check on the very large List we were producing:

def isOrdered(l:List[Int]):Boolean = { l match { 
  case Nil => true
  case x::Nil => true
  case x::y::Nil => x>y
  case x::y::tail => x>y & isOrdered(tail) 
  }
}

It fails with a stackOverflow (how appropriate for a question here!).
I was expecting it to be tail-optimized. What's wrong?

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

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

发布评论

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

评论(4

不忘初心 2024-12-17 22:09:46

isOrdered 不是代码中的最后一个调用, &运营商群岛。试试这个:

@scala.annotation.tailrec def isOrdered(l:List[Int]):Boolean = { l match { 
  case Nil => true
  case x::Nil => true
  case x::y::Nil => x>y
  case x::y::tail => if (x>y) isOrdered(tail) else false
  }
}

isOrdered is not the last call in your code, the & operator is. Try this instead:

@scala.annotation.tailrec def isOrdered(l:List[Int]):Boolean = { l match { 
  case Nil => true
  case x::Nil => true
  case x::y::Nil => x>y
  case x::y::tail => if (x>y) isOrdered(tail) else false
  }
}
困倦 2024-12-17 22:09:46

你的算法不正确。即使 @Kim 进行了改进,isOrdered(List(4,3,5,4)) 仍返回 true

试试这个:(

def isOrdered(l:List[Int]): Boolean = l match {
  case Nil => true
  case x :: Nil => true
  case x :: y :: t => if (x <= y) isOrdered(l.tail) else false
}

也更新了,以便标志正确)

编辑:我的首选布局是这样的:

def isOrdered(list: List[Int]): Boolean = list match {
  case Nil      => true
  case x :: Nil => true
  case x :: xs  => if (x > xs.head) false
                   else isOrdered(xs)
}

如果性能不是问题,快速方法是

def isOrdered(l: List[Int]) = l == l.sorted

Your algorithm is incorrect. Even with @Kim's improvement, isOrdered(List(4,3,5,4)) returns true.

Try this:

def isOrdered(l:List[Int]): Boolean = l match {
  case Nil => true
  case x :: Nil => true
  case x :: y :: t => if (x <= y) isOrdered(l.tail) else false
}

(also updated so that signs are correct)

edit: my perferred layout would be this:

def isOrdered(list: List[Int]): Boolean = list match {
  case Nil      => true
  case x :: Nil => true
  case x :: xs  => if (x > xs.head) false
                   else isOrdered(xs)
}

The quick way if performance isn't a problem would be

def isOrdered(l: List[Int]) = l == l.sorted
救星 2024-12-17 22:09:46

它不能进行尾部优化,因为您返回:'x>y & isOrdered(尾部)'。这意味着需要将其保留在堆栈中。

当您期望函数是尾递归时,使用 @tailrec 注释强制发生错误。它还将解释为什么不能。

It can't be tail-optimized because you return this: 'x>y & isOrdered(tail)'. It means it will need to keep it on the stack.

Use the @tailrec annotation to force an error when you expect functions to be tail-recursive. It will also explain why it can't be.

终弃我 2024-12-17 22:09:46

我认为问题在于您在最后一种情况下使用了按位与运算符(&)。由于运行时需要知道 isOrdered 调用的值才能计算 &,因此它无法对该函数进行尾部优化。 (也就是说,在调用 isOrdered 之后,还有更多的代码要运行——按位与运算。

)或者 if 语句可能会有所帮助。

I think the problem is that you're using the bitwise-and operator (&) in your last case. Since the runtime needs to know the value of the isOrdered call before it can evaluate the &, it can't tail-optimize the function. (That is, there is more code to run--the bitwise-and operation--after isOrdered is called.)

Using && or an if statement may help.

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