-
-
Save aloiscochard/1334040 to your computer and use it in GitHub Desktop.
import Stream._ | |
/** A possibly finite stream that repeatedly applies a given function to a start value. | |
* | |
* @param start the start value of the stream | |
* @param f the function that's repeatedly applied | |
* @return the stream returning the possibly finite sequence of values `start, f(start), f(f(start)), ...` | |
*/ | |
def iterate[A](f: A => A, a: A): Stream[A] = unfold((x: A) => Some((x, f(x))), a) | |
def unfold[A, B](start: B)(f: B => Option[Tuple2[A,B]]): Stream[A] = f(start) match { | |
case Some((elem, next)) => elem #:: unfold(next)(f) | |
case None => empty | |
} | |
// Could be integrated here -> https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_1_final/src//library/scala/collection/immutable/Stream.scala#L647 |
@aloiscochard For what use case is unfold better than iterate?
@missingfaktor's example seems clearer using iterate rather than unfold
Stream.iterate(5)(+1).map(*2).takeWhile(x < 200)
@cvogt for anything where it doesn't make sense to keep asking for stuff indefinitely. In your example, +1
doesn't care if you keep running it forever, so you're safe with an intermediate infinite stream, but in many more realistic use cases, you have a process that you're going to have to repeat until some condition stops being true, and then you need to stop, and that's based on a piece of internal state that is no longer accessible by the time you use takeWhile
. A simple example of a good use case here is a pagination API that hands you a "marker" telling you how to ask for more. You can't just keep asking for more forever and filter later.
Also, unfold
is in some senses the most fundamental operation on a Stream
, much like how fold
(right) is a fundamental operation on List
.
I've just added unfold implementation which could be integrated in std lib