我想为溪流写一个展开。
无法编译,因为它不是尾递归。
@annotation.tailrec
def unfold[A, B](a: A)(f: A => Option[(A, B)]): Stream[B] =
f(a).map { case (a, b) => b #:: unfold(a)(f) }.getOrElse(Stream.empty)
......也没有真正发挥作用。 (不懒惰)
def unfold[A, B](a: A)(f: A => Option[(A, B)]): Stream[B] = {
@annotation.tailrec
def go(state: A, next: Stream[B]): Stream[B] = {
f(state) match {
case Some((a, b)) => go(a, b #:: next)
case None => Stream.empty
}
}
go(a, Stream.empty)
}
// unfold: [A, B](a: A)(f: A => Option[(A, B)])Stream[B]
unfold(0)(i => Some((i+1, i))).take(10).toList
// java.lang.OutOfMemoryError: GC overhead limit exceeded
// at .$anonfun$res3$1(<console>:18)
// at .$anonfun$res3$1$adapted(<console>:18)
// at $$Lambda$1543/299219071.apply(Unknown Source)
// at .go$1(<console>:19)
// at .unfold(<console>:24)
// ... 27 elided
有点难看,通过Iterator
。
def unfold[A, B](a: A)(f: A => Option[(A, B)]): Stream[B] = {
new Iterator[B] {
private var state: Option[A] = Some(a)
private var nextResult: Option[B] = None
def next: B =
nextResult.getOrElse(
throw new NoSuchElementException("next on empty iterator"))
def hasNext: Boolean = {
if (nextResult.isDefined) {
true
} else {
state match {
case Some(s) =>
f(s) match {
case Some((nextState, produced)) =>
nextResult = Some(produced)
state = Some(nextState)
true
case None => false
}
case None => false
}
}
}
}.toStream
}
答案 0 :(得分:2)
def unfold[A, B](a: A)(f: A => Option[(A, B)]): Stream[B] =
f(a).map { case (a, b) => b #:: unfold(a)(f) }.getOrElse(Stream.empty)
这是正确和懒惰的(虽然有些REPL可能会尝试打印所有流)。
Scala流对其tail
进行懒惰评估。我认为你不能以尾递归的方式以懒惰的方式影响流的尾部。然而,这是没有意义的,因为懒惰给你堆栈安全:
assert(unfold(0) { _ => Some((0, 0)) } .toString == "Stream(0, ?)")
assert {
try {
unfold(0) { _ => Some((0, 0)) }.take(1000000).toList
true
} catch {
case _: StackOverflowError => false
}
}