Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy for comprehension evaluation in scala

I'm new to scala and most functional languages and I'm currently trying to factor a number. i've written the code:

lazy val factors = for(int <- 2 until  math.ceil(math.sqrt(number)).toInt if number%int == 0) yield int

I was wondering If I declared the scala val as lazy will it not evaluate the entire for comprehension when I call factors.head?

like image 323
GTDev Avatar asked Dec 16 '22 23:12

GTDev


2 Answers

Your factors variable is lazy; the for comprehension isn't. When you access factors the first time, your for comprehension will be fully evaluated.

In Scala, for comprehension is merely a sugar for flatMap, map, and withFilter method calls. So if your backing data structure is strict (such as Range - which is what you are using), your for comprehension will also be strict. If the data structure is lazy (such as Stream), so will be for comprehension.

Observe the difference:

scala> val number = 50
number: Int = 50

scala> lazy val factors = for(int <- 2 until  math.ceil(math.sqrt(number)).toInt if number%int == 0) yield int
factors: scala.collection.immutable.IndexedSeq[Int] = <lazy>

scala> factors.head
res5: Int = 2

scala> factors
res6: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 5)

scala> lazy val factors = for(int <- Stream.range(2, math.ceil(math.sqrt(number)).toInt - 1) if number%int == 0) yield int
factors: scala.collection.immutable.Stream[Int] = <lazy>

scala> factors.head
res7: Int = 2

scala> factors
res8: scala.collection.immutable.Stream[Int] = Stream(2, ?)
like image 52
missingfaktor Avatar answered Jan 02 '23 21:01

missingfaktor


No. It is a completely different thing: lazy means that the value is computed the first time you access to it. If you want lazy computation for collections, you should use Stream or use a view. A Streamcan be built from a collection using view.

like image 38
Nicolas Avatar answered Jan 02 '23 23:01

Nicolas