尾递归问题
我们正在 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
isOrdered 不是代码中的最后一个调用, &运营商群岛。试试这个:
isOrdered is not the last call in your code, the & operator is. Try this instead:
你的算法不正确。即使 @Kim 进行了改进,
isOrdered(List(4,3,5,4))
仍返回true
。试试这个:(
也更新了,以便标志正确)
编辑:我的首选布局是这样的:
如果性能不是问题,快速方法是
Your algorithm is incorrect. Even with @Kim's improvement,
isOrdered(List(4,3,5,4))
returnstrue
.Try this:
(also updated so that signs are correct)
edit: my perferred layout would be this:
The quick way if performance isn't a problem would be
它不能进行尾部优化,因为您返回:'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.
我认为问题在于您在最后一种情况下使用了按位与运算符(&)。由于运行时需要知道 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.