What are the differences between these statements?
val numbers = List(1, 2, 3, 4)
numbers map println
// vs.
numbers map (x => println(x))
And how does Scala know println will repeatedly take care of each number of numbers?
Thank you.
What are the differences between these statements?
val numbers = List(1, 2, 3, 4) numbers map println // vs. numbers map (x => println(x))
map takes as its argument a function which transforms a single element. map will then apply this function to every element and return a collection with the transformed elements. (Which, BTW, is why this code makes no sense: a) the return value of map is ignored, and b) println always returns Unit, so you will end up with a list of Units. foreach would be the correct method to use here.)
In your second example, you pass a λ (an anonymous first-class function object) to map.
In the first example, what exactly do you pass to map? It looks like you are passing a method, but that cannot be: a) map takes a function, not a method, and b) methods aren't objects, so you simply can't pass them around anyway. You have to somehow convert and/or wrap the method to/in a function.
In your second example, you are doing that very explicitly: you have a function which calls the method. The first example is more implicit. Scala has a feature called η-expansion, that lets you "lift" a method to function, which will partially apply the method to its implicit this argument, but leave its other (regular) parameters unbound.
The syntax for this is the ubiquitous underscore: foo.bar _ means "take the method bar of foo, bind its this to foo and convert it into a function". In this particular case, you take println, bind its this to the top-level REPL context object (which doesn't really matter, since println doesn't actually care about its this, it is used like a procedure) and turn it into a function.
But wait, there's no underscore? That's right. In cases where the Scala compiler can determine that you don't actually want to call the method but wrap it into a function (i.e. when you don't pass an argument list, the method expects an argument list, and the context expects a type that is compatible with the type of the method), then Scala will perform implicit η-expansion for you.
So, let's get back to your question:
What are the differences between these statements?
Well, on the one hand, the differences are what I described above: the first example uses implicit η-expansion, the second example uses an explicit λ. OTOH, there are no differences: both of them create a function from the println method, the second one just does it in a more convoluted way.
And how does Scala know println will repeatedly take care of each number of numbers?
It doesn't. a) it's not println that "takes care of each number", it's map that does it, and b) Scala doesn't know anything, that's just how map was written.
Very simplistic, map looks like this:
sealed trait MyList[+T] {
def map[U](function: T ⇒ U): MyList[U]
def foreach(procedure: T ⇒ Unit)
}
case object EmptyList extends MyList[Nothing] {
// mapping the empty list returns the empty list
def map[U](function: Nothing ⇒ U) = EmptyList
def foreach(procedure: Nothing ⇒ Unit) = ()
}
final case class ListCell[+T](first: T, rest: MyList[T]) extends MyList[T] {
// mapping a non-empty list returns the result of transforming the first
// element of the list and recursively mapping the rest of the list
def map[U](function: T ⇒ U) = ListCell(function(first), rest map function)
def foreach(procedure: T ⇒ Unit) = { procedure(first); rest foreach procedure }
}
And here's how we use our simple little list:
val list: MyList[Short] = ListCell(1, ListCell(2, ListCell(3, EmptyList)))
list map (1+)
// => ListCell(2, ListCell(3, ListCell(4, EmptyList)))
list map(_.toString)
// => ListCell(1, ListCell(2, ListCell(3, EmptyList)))
list map println
// 1
// 2
// 3
// => ListCell((), ListCell((), ListCell((), EmptyList)))
// here you can see the useless list of Units that is returned
list foreach println
// 1
// 2
// 3
// foreach just returns nothing
map is expecting a function that that a value and produces a value. In your first example, you provide such a function explicitly by giving a lambda. In the second case, the compiler can inspect the types and see that println : A => Unit. Note that normally, you would not want to use map for a function that produces Unit, that's more appropriate to foreach.
The two statements have the same semantic, the second version just add a level of indirection that is not actually required for things to work.
The thing is that the map function takes as an argument a function able to operate on an Int and producing a Unit:
final def map[B](f: (A) ⇒ B): List[B]
In your example A is Int and B is Unit.
Now if you take a look at the signature of the println method and the one of your anonymous function, you'll notice that they are actually the same:
def println(x: Any): Unit
(x => println(x)): Any -> Unit
What is happening is that the map function iterates through the element in the list and for each element x it calls the function f(x). Since both println and the anonymous function accept Any as an input map can safely pass them the x Int.
Using the anonymous function you are just adding an intermediate function call step.
println) which already does what you want, and then you wrap it in an anonymous function (a lambda expression) which does nothing more than pass on the argument toprintln. - Jesperprintlnis not a function, it's a method. You can't pass a method around, methods aren't objects in Scala. So, you have to wrap it in a function anyway. You can do this via η-expansion using the_underscore (println _), or, if Scala can infer from the context that you don't want to call the method but instead convert it to a function (as is the case here), then it will perform implicit η-expansion for you. Either way, whether you use explicit η-expansion, implicit η-expansion or an explicit λ, you have to create a function from the method. - Jörg W Mittag