Created
November 22, 2017 11:41
-
-
Save MarounMaroun/a0f6d7b972cbf73059115fd35776aaea to your computer and use it in GitHub Desktop.
Strict VS Lazy evaluation in Scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Assume we are interested in finding the first two even numbers in a very big file. | |
* Since we love functional programming, we don't want to use the traditional for loops. | |
* Instead, we want to apply a series of function to get the desired output. | |
*/ | |
// for the sake of the example, I assume the input is found in a list, not a file | |
var l = List(1, 47, 38, 53, 51, 67, 39, 46, 93, 54, 45, 33, 87, 96, 100, 4, 84, 17, 31, 81, 88, 35, 36) | |
// we don't really need toList here, but since we're assuming the data is coming from a file, I'll use it anyway | |
var strict_result = l.toList.filter(_ % 2 == 0).take(2) | |
// great! The result printed is 38 and 46 | |
strict_result foreach println | |
// but did you notice how the list was created? | |
// OK, that's what really happened: | |
// 1. we opened the file (not really) | |
// 2. got ALL the lines (by using toList) | |
// 3. we filtered ALL the lines to get even numbers | |
// 4. finally we took the first two numbers | |
// that's because the List is a strict data structure. So when we call toList, it evaluates *immediately*, | |
// and only when we have the whole list (file lines in our original assumption), it does the filtering | |
// so what we should do? You guessed it right! We should be using a data structure that is *lazy* evaluated. | |
// Stream for the rescure! | |
var lazy_result = l.toStream.filter(_ % 2 == 0).take(2) | |
// in order to better understand what happened here, let's try the following | |
l.toStream | |
// prints "scala.collection.immutable.Stream[Int] = Stream(1, ?)" | |
// what is this? toStream evaluates to only one element - the first item in the list. | |
// the next element is "?", which indicates that the stream has not evaluated the next element, | |
// and that's because toStream is a lazy function, and the next line (list item in this case) is evaluated when we use it. | |
// now when we apply the "filter" function, it will start reading next line until we get the FIRST even number. | |
// when we apply "take(2)", no action is performed, but it knows that it should pick two numbers. It doesn't evaluate until | |
// we use both numbers: | |
strict_result foreach println | |
// now if we print laze_result, we should get the full result: | |
lazy_result | |
// prints "scala.collection.immutable.Stream[Int] = Stream(38, 46)" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment