How Immutability is Achieved in Scala Streams? - scala

It might become silly but I have question regarding to Scala Stream evaluation in immutable fashion.
Lets say I have a Stream like this (All lines executed in repl);
val a = Stream(1,2,3,4,5,6,7,8,9,10);
a: scala.collection.immutable.Stream[Int] = Stream(1, ?)
When I run following lines;
a(3);
a
I get ;
scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)
My first question is how this immutable structure gets changed ? I mean if did like this (assuming variable 'a' defined as 'var');
a = a(3) I might expect such result.
My other question is when I run following lines;
val a = Stream(1,2,3,4,5,6,7,8,9,10);
a: scala.collection.immutable.Stream[Int] = Stream(1, ?)
val b = a;
b: scala.collection.immutable.Stream[Int] = Stream(1, ?)
b(5);
scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, 5, 6, ?)
a
scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, 5, 6, ?)
As you can see in last part after executing 'a', its seems changed again.
If I try this kind of assignment with List type (as far as I know List is strict version of Stream) and do some transformation like drop,take etc.)
val a = List(1,2,3,4,5)
val b = a;
b.dropRight(1)
variable 'a' and 'b' still is still List(1,2,3,4,5)
So how this happened and what is the point that I'm missing ?

Scala Streams provide memoization - they are like lazy lists, but once elements have been generated, they are stored for future retrieval.
So when you "force" the Stream b to evaluate some of its elements by requesting the element at index 5, the original Stream a (which is the same Stream object) is also forced.
Key point: doing this doesn't modify the stream (it remains immutable), it just changes which elements have been evaluated and are memoized.
Your Stream(1,?) and Stream(1,2,3,4,5,6,?) are the same stream, just evaluated to a different degree:
scala> val a = Stream(1,2,3,4,5,6,7,8,9,10);
a: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> val b = a
scala> a(3)
res9: Int = 4
scala> a
res10: scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)
scala> b
res11: scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)
scala> Stream(1,2,3,4,5,6,7,8,9,10) == a
res12: Boolean = true
scala> Stream(1,2,3,4,5,6,7,8,9,10) == b
res13: Boolean = true

Related

Scala Iterator.takeWhile is dropping the failed element

val i = (1 to 8).toIterator
val oneToThree = i.takeWhile(_ <= 3).toList
// List(1, 2, 3)
So far so good.
Now I want the iterator to still contain (3, 4, 5, 6, 7, 8), but if I carry on:
val fourToSix = i.takeWhile(_ <= 6).toList
// List(5, 6)
Element 3 has gone missing. I would preferably like fourToSix to be List(4, 5, 6). How can I use takeWhile or some similar operation so that this works?
Note that the documentation on takeWhile states:
Reuse: After calling this method, one should discard the iterator it
was called on, and use only the iterator that was returned. Using the
old iterator is undefined, subject to change, and may result in
changes to the new iterator as well.
So you shouldn't use i, after calling takeWhile on it.
But to achieve what you want you can use the span method:
scala> val i = (1 to 8).iterator
i: Iterator[Int] = non-empty iterator
scala> val (oneToThree, rest) = i.span(_ <= 3)
oneToThree: Iterator[Int] = non-empty iterator
rest: Iterator[Int] = unknown-if-empty iterator
scala> oneToThree.toList
res1: List[Int] = List(1, 2, 3)
scala> val fourToSix = rest.takeWhile(_ <= 6)
fourToSix: Iterator[Int] = non-empty iterator
scala> fourToSix.toList
res2: List[Int] = List(4, 5, 6)

Using Stream as a substitute for loop

scala> val s = for(i <- (1 to 10).toStream) yield { println(i); i }
1
s: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> s.take(8).toList
2
3
4
5
6
7
8
res15: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8)
scala> s.take(8).toList
res16: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8)
Looks like Scala is storing stream values in memory to optimize access. Which means that Stream can't be used as a substitute for imperative loop as it will allocate memory. Things like (for(i <- (1 to 1000000).toStream, j <- (1 to 1000000).toStream) yield ...).reduceLeft(...) will fail because of memory. Was it wrong idea to use streams this way?
You should use Iterator instead of Stream if you want a loop-like collection construct. Stream is specifically for when you want to store past results. If you don't, then, for instance:
scala> Iterator.from(1).map(x => x*x).take(10).sum
res23: Int = 385
Methods continually, iterate, and tabulate are among the more useful ones in this regard (in the Iterator companion object).

How can I use a Scala List as a Stack?

I am trying to solve a hw problem in Scala. A traditional solution require a stack but stacks have not been introduced in the class so far. Only lists have been introduced. My question is how can treat a list as a stack? In other words, how can I mimic pushing and popping elements on a list?
I hope this will show the idea:
scala> val x = List(1,2,3)
x: List[Int] = List(1, 2, 3)
scala> val pushed0 = 0::x
push3: List[Int] = List(0, 1, 2, 3)
scala> val pop0 = pushed0.head
pop3: Int = 0
// it is actually more peek than fair pop
scala> val stackAfterPop = pushed0.tail
stackAfterPop: List[Int] = List(1, 2, 3)
It will actually have much better syntax when you'll be acquainted with pattern matching (next week I guess):
scala> val popped::stack = pushed0
popped: Int = 0
stack: List[Int] = List(1, 2, 3)

How to start a Scala stream some distance "in" (ala takeWhile)?

The question Why does my takeWhile fail to work with my Stream makes it clear that takeWhile() is lazy:
Stream.from(1).takeWhile(_ < 5) //Stream(1, ?)
But for that question the solution seemed to be that one could use toList to force evaluation as desired. But what if you want, not a list or specific value, but the continuing Stream?
It would seem that I could do it by forcing evaluation until I found the desired value and then instantiate the Stream again and use index but surely there's a better way?
UPDATE: Apparently my phrasing was confusing; I wanted the solution provided by dropWhile.
You can use span:
scala> val (before, after) = Stream.from(1).span(_ < 5)
before: scala.collection.immutable.Stream[Int] = Stream(1, ?)
after: scala.collection.immutable.Stream[Int] = Stream(5, ?)
Or, if you only care about "the continuing stream", dropWhile:
scala> val after = Stream.from(1).dropWhile(_ < 5)
after: scala.collection.immutable.Stream[Int] = Stream(5, ?)
It seems you are looking for force:
scala> val s = Stream.from(1).takeWhile(_<10)
s: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> s.force
res84: scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, 5, 6, 7, 8, 9)
It's very difficult to understand what you are asking for -- as can be seen by everyone answering a different thing. Here's the answer to another possible interpretation: you want the stream starting at a value. Well, in this case, you can do this:
scala> Stream.from(1).dropWhile(_ < 5) //Stream(1, ?)
res3: scala.collection.immutable.Stream[Int] = Stream(5, ?)

What is the difference between val b=a (a is an Array) and val b=a.clone()?

I am reading scaladocs and just wondering difference between direct assignment and .clone method.
val a=Array(1,2,3,4,5)
case 1:
val b=a
case 2 :
val b=a.clone()
Consider this:
scala> val a=Array(1,2,3,4,5)
a: Array[Int] = Array(1, 2, 3, 4, 5)
scala> val b = a
b: Array[Int] = Array(1, 2, 3, 4, 5)
scala> val c = a.clone()
c: Array[Int] = Array(1, 2, 3, 4, 5)
scala> b(0) = 0
scala> c(1) = 1
scala> a
res2: Array[Int] = Array(0, 2, 3, 4, 5)
scala> b
res3: Array[Int] = Array(0, 2, 3, 4, 5)
scala> c
res4: Array[Int] = Array(1, 1, 3, 4, 5)
As you can see, when you do val b = a, then a and b point to the same object. When the object is changed, the change will be seen by both.
On the other hand, when you clone the array, you produce a new array with the same content. Changing this new array does not change the old one.
I believe case 1 just sets the reference of a to b while case 2 creates an entirely new array that is a copy of a and putting the value in b.
In other words if you in case a edit the a array the b array will also be edited this is not the case in case 2
Here is an answer in code:
scala> val a = Array(1,2,3,4,5)
scala> a.hashCode()
res12: Int = 1382155266
scala> val b = a
scala> b.hashCode()
res13: Int = 1382155266
scala> val c = a.clone()
scala> c.hashCode()
res14: Int = 2062756135
scala> a eq b
res15: Boolean = true
scala> a eq c
res16: Boolean = false
scala> b eq c
res17: Boolean = false
In case 1, both reference leads to the same object while in the second case, a new object is created and a and b do not reference the same object.