In Scala, is there a way to get the items that are currently being evaluated in the stream?

Is there a way in Scala to get the items currently being evaluated in the stream? For example, in Stream

val s: Stream[Int] = Stream.cons(1, Stream.cons(2, Stream.cons(3, s.map(_+1)))) 

the method should only return List(1,2,3) .

+6
scala stream lazy-evaluation
source share
4 answers

In 2.8, there is a protected method called tailDefined that will return false when you go to a point in a stream that has not yet been evaluated.

This is not very useful (unless you want to write your own Stream class), except that Cons makes this method publicly available. I am not sure why it is protected in Stream and not in Cons - I think that one or the other may be a mistake. But at the moment, at least you can write such a method (writing the functional equivalent is left as an exercise for the reader):

 def streamEvalLen[T](s: Stream[T]) = { if (s.isEmpty) 0 else { var i = 1 var t = s while (t match { case c: Stream.Cons[_] => c.tailDefined case _ => false }) { i += 1 t = t.tail } i } } 

Here you can see it in action:

 scala> val s = Stream.iterate(0)(_+1) s: scala.collection.immutable.Stream[Int] = Stream(0, ?) scala> streamEvalLen(s) res0: Int = 1 scala> s.take(3).toList res1: List[Int] = List(0, 1, 2) scala> s res2: scala.collection.immutable.Stream[Int] = Stream(0, 1, 2, ?) scala> streamEvalLen(s) res3: Int = 3 
+7
source share

Rex based solution:

 def evaluatedItems[T](stream: => Stream[T]): List[T] = { @tailrec def inner(s: => Stream[T], acc: List[T]): List[T] = s match { case Empty => acc case c: Cons[T] => if (c.tailDefined) { inner(c.tail, acc ++ List(c.head)) } else { acc ++ List(c.head) } } inner(stream, List()) } 
+5
source share

Enter this operator in the interactive shell, and you will see that it evaluates the value of s: Stream[Int] = Stream(1, ?) . So, in fact, the other two elements 2 and 3 are not yet known.

When accessing additional elements, more flow is calculated. So now put s(3) in a shell that will return res0: Int = 2 . Now put s in the shell and you will see the new value res1: Stream[Int] = Stream(1, 2, 3, 2, ?) .

The only method I could find that contained the information you wanted was, unfortunately, s.toString . With some parsing, you can return items from a string. This is a barely acceptable solution with just ints, and I could not imagine any general solution using the idea of ​​parsing strings.

+3
source share

Using scanLeft

  lazy val s: Stream[Int] = 1 #:: s.scanLeft(2) { case (a, _) => 1 + a } 
0
source share

All Articles