【发布时间】:2012-11-25 16:46:21
【问题描述】:
我正在尝试用 Scala 做一些实验。我想重复这个实验(随机),直到出现预期的结果并得到那个结果。如果我使用 while 或 do-while 循环执行此操作,那么我需要编写(假设“body”代表实验,“cond”表示是否符合预期):
do {
val result = body
} while(!cond(result))
但是,它不起作用,因为最后一个条件不能引用循环体中的局部变量。我们需要像这样稍微修改一下这个控制抽象:
def repeat[A](body: => A)(cond: A => Boolean): A = {
val result = body
if (cond(result)) result else repeat(body)(cond)
}
它以某种方式工作,但对我来说并不完美,因为我需要通过传递两个参数来调用此方法,例如:
val result = repeat(body)(a => ...)
我想知道是否有更有效、更自然的方式来做到这一点,让它看起来更像一个内置结构:
val result = do { body } until (a => ...)
没有返回值的 body 的一个很好的解决方案可以在这篇文章中找到:How Does One Make Scala Control Abstraction in Repeat Until?,最后一个单行答案。该答案中的body 部分不返回值,因此until 可以是新AnyRef 对象的方法,但该技巧不适用于此处,因为我们希望返回A 而不是@ 987654330@。有什么办法可以做到这一点?谢谢。
【问题讨论】:
-
为什么你不喜欢这段代码中的递归?它是尾递归,所以堆栈不会增长。
-
我对尾递归优化不太有信心。我曾经使用该技术编写了一个 BFS 算法,它仍然会堆栈溢出。我可能会就此发表另一个问题。无论如何,这只是一个小问题,我确实想看看如何让我的代码看起来更原生。
-
如果你得到一个stackoverflow,它不是尾递归的。您可以通过添加
@annotation.tailrec告诉编译器一个方法应该是尾递归的。如果不是,编译器将失败。 -
谢谢,我刚刚解决了这个问题。我在没有 final 关键字的抽象类中定义了尾递归函数。编译器没有做任何优化,所以会溢出。
标签: scala