Lai*_*uan 3 functional-programming scala
通常while循环的样板看起来像(r
是我想要的结果,p
是预测器:
var r, p;
while(p()) {
(r, p) = compute(r)
}
Run Code Online (Sandbox Code Playgroud)
我可以将其转换为递归以摆脱var
:
def f(r) = {
val (nr, p) = compute(r)
if(p()) nr
else f(nr)
}
Run Code Online (Sandbox Code Playgroud)
有没有内置的方法来实现这种逻辑?我知道Iterator.continually
,但似乎仍然需要var
存储副作用。
def compute(i: Int): (Int, () => Boolean) =
(i - 1) -> { () => i > 1 }
Run Code Online (Sandbox Code Playgroud)
要创建一个不可变的,while
您将需要iteration
- 一个接受state
并返回state
相同类型的新函数以及退出条件的函数。
这不是最好的解决方案 - 在我看来,这段代码很难阅读,但既然你提到了它:
val (r, p) = Iterator.continually(()).
scanLeft( 13 -> { () => true } ){
case ((r, p), _) => compute(r)
}.dropWhile{ case (r, p) => p() }.
next
// r: Int = 0
// p: () => Boolean = <function0>
Run Code Online (Sandbox Code Playgroud)
您可以使用,val (r, _) =
因为您不需要p
.
如果你想了一个办法Iterator
看到这个答案用Iterator.iterate
。
我想这是一个惯用的解决方案。您始终可以将while
循环重写为具有显式状态类型的尾递归:
@annotation.tailrec
def lastWhile[T](current: T)(f: T => (T, () => Boolean)): T = {
val (r, p) = f(current)
if (p()) lastWhile(r)(f)
else r
}
lastWhile(13){ compute }
// Int = 0
Run Code Online (Sandbox Code Playgroud)
如果您正在使用scalaz
,已经有这样的方法。它产生一个Stream
,所以你应该得到最后一个元素。
在迭代结束时,您应该使用流元素 ( ) 和下一个状态生成Option
(None
是退出条件) :Pair
r
(r, p())
unfold(13 -> true) { case (r0, p0) =>
val (r, p) = compute(r0)
p0.option(r -> (r, p()))
}.last
// Int = 0
Run Code Online (Sandbox Code Playgroud)