Why my function is not being print after map?

55 Views Asked by At

I am trying to figure it out how to chain functions in Scala.

I have the following code:

def multiPrint(list: List[Int], number: Int): Unit = {
    list
      .map(x => x * number)
      .andThen(x => print(x))
  }

but this does not print a result as I expected. It prints "()" like if it was an empty list.

Then I tried like:

  def multiPrint(list: List[Int], number: Int): Unit = {
      list
        .toStream
        .map(x => x * number)
        .print
  }

This works, but toStream is deprecated. Anyway, I would like to do it with andThen. Any idea?

3

There are 3 best solutions below

0
Dima On BEST ANSWER

As the other answer mentioned, you are looking for foreach ... But I thought, I'd explain what andThen actually does here, which is kinda interesting.

So, if you look at a signature of andThen:

trait PartialFunction[A, B] extends (A => B) { 
...
   def andThen[C](k: B => C): PartialFunction[A, C]
...
}

it should become clear that it doesn't do what you think it does. It is actually a partial function combinator: given two partial functions, one f1: A => B, and and another f2: B => C, it creates and returns a third function, A => C, that first calls f1 with the given argument, and then invokes f2 with the result of execution of f1.

So,

 list
      .map(_ * number)
      .andThen(print(_))

Does not really print anything at all (I am guessing your saw () in the output when because you tried to print out the result of multiPrint, which is a Unit.

But, if you try something like this:

val foo = Seq(1,2,3).map(_ * 2).antThen(print(_))
foo(1)

You may get mildly surprised because this prints 4. foo(2) will print 6. and foo(3)? It throws an IndexOutOfBoundException which may give you a hint on what's really going on.

Seq[Int] in scala is actually a PartialFunction[Int, Int], that returns the Seq element at the index given by the argument. Your .andThen combined that function with print, and created a new function foo, that accesses the element of the result of .map at the given index, andThen prints the result.

So, foo(1) for instance, gets the element at index 1, which is 2*2, and prints 4. And foo(3) fails, because index 3 does not exist.

A note just for the sake of completness:

As the other answer mentions, to print out elements of seq one-by-one, just use foreach: Seq(1,2,3).map(_ *2).foreach(println)

0
marstran On

If you want the same format as .toStream.print, then use mkString(", ") and then print the resulting string:

def multiPrint(list: List[Int], number: Int): Unit = {
    val string = list.map(x => x * number).mkString(", ")
    print(string)
}
0
stefanobaghino On

The function you are looking for it foreach, which is the "cousin" of map which rather than transforming a collection applies some sort of side effect (like printing).

def multiPrint(list: List[Int], number: Int): Unit = {
    list
      .map(x => x * number)
      .foreach(print)
  }

multiPrint(List(1,2,3), 2) // prints 246

You can play around with this code here on Scastie.

Remember to use println if you want to have a newline after each number. ;-)