The learning curve for FS2 is steep and comparing it to Scala's built-in streams is not helpful. Given this Scala stream to generate Fibonacci numbers:
val f: Stream[Int] = 0 #:: 1 #:: f.zip(f.tail).map { case (x, y) => x + y }
you might think you can do this:
val spliced = f.take(5) ++ f.drop(5)
and treat spliced as normal:
println(spliced.take(10).mkString(", ")) // 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
And you'd be correct when working with Scala streams but not for FS2 streams, that is s != s.take(n) ++ s.drop(n)
Fabio Labella @SystemFwThat is, s.take(n) ++ s.drop(n) will return the same values as Scala's streams but evaluate different effects to what you might expect.
I mean, this is certainly not the case in general, since the RHS reevaluates s twice
For example, if we had a stream:
rangeStream(6).evalMap { x =>
IO {
println(s"x = $x")
x
}
}
then s.take(3) ++ s.drop(3) would indeed return a Stream containing 1,2,3,4,5,6 but you'd see this printed out:
x = 1
x = 2
x = 3
x = 1
x = 2
x = 3
x = 4
x = 5
x = 6
As Fabio says "you can use Pull if you want 'take some, then give me the rest' semantics". So, this is what I did here on GitHub.
Aside: the reason I want to splice an FS2 Stream is to introduce some test assertions. Here, I want the opposite of the above, namely to evaluate the effect (my assertion in this case) but to ignore the value. Here, one can use
Stream.eval_
Note the underscore. However, be a bit careful here as if there is no value returned, calls like myStream.take may semantically block.
No comments:
Post a Comment