Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

println in scala for-comprehension

In a for-comprehension, I can't just put a print statement:

def prod (m: Int) = {   for (a <- 2 to m/(2*3);     print (a + "  ");     b <- (a+1) to m/a;     c = (a*b)      if (c < m)) yield c } 

but I can circumvent it easily with a dummy assignment:

def prod (m: Int) = {   for (a <- 2 to m/(2*3);     dummy = print (a + "  ");     b <- (a+1) to m/a;     c = (a*b)      if (c < m)) yield c } 

Being a side effect, and only used (so far) in code under development, is there a better ad hoc solution?

Is there a serious problem why I shouldn't use it, beside being a side effect?

update showing the real code, where adapting one solution is harder than expected:

From the discussion with Rex Kerr, the necessity has risen to show the original code, which is a bit more complicated, but did not seem to be relevant for the question (2x .filter, calling a method in the end), but when I tried to apply Rex' pattern to it I failed, so I post it here:

  def prod (p: Array[Boolean], max: Int) = {     for (a <- (2 to max/(2*3)).         filter (p);       dummy = print (a + "  ");       b <- (((a+1) to max/a).          filter (p));       if (a*b <= max))          yield (em (a, b, max)) } 

Here is my attempt -- (b * a).filter is wrong, because the result is an int, not a filterable collection of ints:

  // wrong:    def prod (p: Array[Boolean], max: Int) = {     (2 to max/(2*3)).filter (p).flatMap { a =>       print (a + " ")       ((a+1) to max/a).filter (p). map { b =>          (b * a).filter (_ <= max).map (em (a, b, max))       }     }   } 

Part II belongs to the comments, but can't be read, if written there - maybe I delete it in the end. Please excuse.

Ok - here is Rex last answer in code layout:

  def prod (p: Array[Boolean], max: Int) = {     (2 to max/(2*3)).filter (p).flatMap { a =>       print (a + " ")       ((a+1) to max/a).filter (b => p (b)          && b * a < max).map { b => (m (a, b, max))       }     }   }   
like image 339
user unknown Avatar asked Sep 14 '11 08:09

user unknown


People also ask

How for comprehension works Scala?

Scala offers a lightweight notation for expressing sequence comprehensions. Comprehensions have the form for (enumerators) yield e , where enumerators refers to a semicolon-separated list of enumerators. An enumerator is either a generator which introduces new variables, or it is a filter.

What is a for comprehension in Scala?

Comprehensions is a construct in Scala which allows us to evaluate certain expressions. The For Comprehension has the form for (enumerators) yield e , where enumerators refer to a semi-colon separated list of enumerators. An enumerator can either be a generator that iterates the list or a filter.

What is the use of yield keyword in Scala for comprehension?

yield keyword will returns a result after completing of loop iterations. The for loop used buffer internally to store iterated result and when finishing all iterations it yields the ultimate result from that buffer.

What operations is a for comprehension syntactic sugar for?

Finally, we discovered that a for-comprehension is just syntactic sugar for a sequence of calls to methods foreach, map, flatMap, and withFilter.


2 Answers

Starting Scala 2.13, the chaining operation tap, has been included in the standard library, and can be used with minimum intrusiveness wherever we need to print some intermediate state of a pipeline:

import util.chaining._  def prod(m: Int) =   for {     a <- 2 to m / (2 * 3)     b <- (a + 1) to (m / a.tap(println)) // <- a.tap(println)     c =  a * b     if c < m  } yield c  prod(20) // 2 // 3 // res0: IndexedSeq[Int] = Vector(6, 8, 10, 12, 14, 16, 18, 12, 15, 18) 

The tap chaining operation applies a side effect (in this case println) on a value (in this case a) while returning the value (a) untouched:

def tap[U](f: (A) => U): A


It's very convenient when debugging as you can use a bunch of taps without having to modify the code:

def prod(m: Int) =   for {     a <- (2 to m.tap(println) / (2 * 3)).tap(println)     b <- (a + 1) to (m / a.tap(println))     c = (a * b).tap(println)     if c < m  } yield c 
like image 37
Xavier Guihot Avatar answered Oct 02 '22 16:10

Xavier Guihot


This is how you need to write it:

scala> def prod(m: Int) = {      |   for {      |     a <- 2 to m / (2 * 3)      |     _ = print(a + " ")      |     b <- (a + 1) to (m / a)      |     c = a * b      |     if c < m      |   } yield c      | } prod: (m: Int)scala.collection.immutable.IndexedSeq[Int]  scala> prod(20) 2 3 res159: scala.collection.immutable.IndexedSeq[Int] = Vector(6, 8, 10, 12, 14 , 16, 18, 12, 15, 18) 
like image 130
missingfaktor Avatar answered Oct 02 '22 14:10

missingfaktor