Search code examples
scalafunctional-programmingfor-comprehension

Assignment expression in for/yield cause of Scala?


My codes looks like this:

  type Occurrences = List[(Char, Int)]
  def subtract(x: Occurrences, y: Occurrences): Occurrences = for {
    (theChar, theInt) <- x
    yMap = y.toMap
    finalInt = theInt - yMap.getOrElse(theChar,0)
    if finalInt != 0
  } yield (theChar, finalInt)

I was wondering whether yMap= y.toMap is evaluated only once or many times.. If it was evaluated many times, what would be the correct syntax to make it to be evaluated only once?


Solution

  • Short Answer

    Just bring the ymap = y.toMap part out of the for comprehension.

    def subtract(x: Occurrences, y: Occurrences): Occurrences = {
        val yMap = y.toMap
        for {
          (theChar, theInt) <- x
          finalInt = theInt - yMap.getOrElse(theChar, 0)
          if finalInt != 0
        } yield (theChar, finalInt)
      }
    

    Detailed Answer

    Scala For Comprehensions is just a syntactic sugar.

    For instance your code will be translated to the following code by compiler (not exactly the following code but the concept is the same):

    def subtract(x: Occurrences, y: Occurrences): Occurrences = x map {
        case (theChar, theInt) =>
          def yMap = y.toMap
          def finalInt = theInt - yMap.getOrElse(theChar, 0)
          (theChar, finalInt)
      } filter {
        case (_, theInt) =>
          theInt != 0
      }
    

    So any expression inside the map part will be executed for every item of the collection (x in this case). By moving the y = y.toMap part out of the for block the code will be translated into :

      def subtract(x: Occurrences, y: Occurrences): Occurrences = {
        def yMap = y.toMap
        x map {
          case (theChar, theInt) =>
            def finalInt = theInt - yMap.getOrElse(theChar, 0)
            (theChar, finalInt)
        } filter {
          case (_, theInt) =>
            theInt != 0
        }
      }
    

    which is most probably what you really want.