3

I am trying to understand how to perform an operation when using foreach. For e.g. how can I print element+1 of alist using foreach

scala>alist = List(1,3,5,7)
scala>alist.foreach(println(_+1)) #=> error: missing parameter type...
scala>alist.foreach(println(_).toInt + 1) #=> error: toInt is not a member of Unit

I understand there are alternatives (below) but I am trying if it can be done using foreach.

scala>for(x<-alist) println(x+1)  #=> 2,4,6,8
scala>alist.map(x => println(x + 1)) #=> 2,4,6,8 
Bala
  • 11,068
  • 19
  • 67
  • 120
  • In the first foreach, just explicitly say the type using an annotation. In the second, `println` returns Unit, which you're then trying to access the `toInt` method of. – Carcigenicate Jan 02 '17 at 16:09
  • @Carcigenicate could you please throw me an example? – Bala Jan 02 '17 at 16:12
  • It's a bit confusing, since your question is " how can I add +1" but your example doesn't do that ! – C4stor Jan 02 '17 at 16:18
  • @C4stor You are right. I have edited my question to say I just need to access each element, do some operation and print it. – Bala Jan 02 '17 at 16:21

4 Answers4

5

For e.g. how can I add +1 to each element of a list using foreach

Edit:

To answer your updated question, you can definitely use foreach:

alist.foreach(x => println(x + 1))

You can't use placeholder syntax inside println since the compler infers it as:

alist.foreach(x => println(x => x + 1))

According to it's expansion laws. println takes a parameter of type Any, so it can't bind it to a concrete type with a plus method.

If you're interested in the rules of placeholder syntax, see Hidden features of Scala


You cannot mutate a List[+A] using foreach in Scala, since lists are immutable and foreach return type is Unit. What you can do is project a new list from an existing one using the map transformation:

scala> val list = List(1,2,3,4)
list: List[Int] = List(1, 2, 3, 4)

scala> val plusOneList = list.map(_ + 1)
plusOneList: List[Int] = List(2, 3, 4, 5)

If you look at the signature for foreach, you see that it takes a function: A => Unit, which takes an element of type A and projects back a Unit. This signature is a sign for a side effecting method and since list is immutable, that doesn't help us.

If you used a mutable list, such as ListBuffer, then you could use side effects for population:

scala> val listBuffer = mutable.ListBuffer[Int]()
listBuffer: scala.collection.mutable.ListBuffer[Int] = ListBuffer()

scala> (0 to 4).foreach(x => listBuffer += x)

scala> listBuffer
res10: scala.collection.mutable.ListBuffer[Int] = ListBuffer(0, 1, 2, 3, 4)
Community
  • 1
  • 1
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • The OP edited the question and clarified their initial intent. Now your post answers a different question. – Hristo Iliev Jan 02 '17 at 17:14
  • @HristoIliev It is generally bad to modify a question after people have already answered it, don't you agree? – Yuval Itzchakov Jan 02 '17 at 17:15
  • If the question is ambiguous, one has to ask the OP to clarify it and answer once the ambiguity is removed. Otherwise, one risks answering a different question. – Hristo Iliev Jan 02 '17 at 17:21
  • @HristoIliev I agree, although it took the OP quite some time to restate his question. Anyway, I've modified my answer to reflect the new question. – Yuval Itzchakov Jan 02 '17 at 17:22
2

My Scala is exceedingly rusty, and I don't have a medium to test the code on, so please notify me of any syntax issues.

Scala has issues automatically inferring the type of parameters of anonymous functions in some circumstances. From my experience, it's best to just say the types explicitly, else risk recieving the wrath of the compiler. If all you're trying to do is add one to each element and print the result, try:

alist.foreach(
    n: Int => println(n + 1)
)

Note the purpose of foreach though. It is intended to be used when you want to carry out side effects over a list. If your intent was to create a second list where each element is + 1 the original list, use a generator/map function instead.

And regarding your second example, if you think on it, it will be clear why it doesn't work. println returns void/Unit, which you then try to access the toInt method of.

Edit:

As noted in the comments, in this case, type annotations aren't required. I still prefer to place them though. I prefer explicit types unless they're bloating the code (personal choice).

Carcigenicate
  • 43,494
  • 9
  • 68
  • 117
  • Scala usually uses Int instead of Integer (which is correct, but comes from Java) – C4stor Jan 02 '17 at 16:14
  • OP is asking how to append 1 to each element in the list, not how to print it. – Yuval Itzchakov Jan 02 '17 at 16:15
  • @YuvalItzchakov The OP's examples say otherwise. I'll address the action of `foreach`, but I don't believe he intends to append the summed numbers to anything. – Carcigenicate Jan 02 '17 at 16:18
  • @YuvalItzchakov I addressed the difference between `for` and `foreach`. – Carcigenicate Jan 02 '17 at 16:21
  • Downvoter, please comment. If the issue is petty enough that it wasn't worth your time to comment, it's probably too petty to justify the downvote in the first place. – Carcigenicate Jan 02 '17 at 16:48
  • Scala does not **always** have problems inferring the types, only in some cases. (Note: I didn't downvote) – Hristo Iliev Jan 02 '17 at 17:16
  • @HristoIliev I have a bad habit of stating absolutes. I mentioned that because I remember when I started writing Scala after I had learned Haskell, I was continually frustrated by ita inability to infer parameter types in situations like these. I'll soften my answer at that part. – Carcigenicate Jan 02 '17 at 17:20
  • This is not a case of Scala not being able to infer the parameter type, rather an incorrect use of `_`. `alist.foreach(x => println(x + 1))` works without specifying the type of `x`. – Hristo Iliev Jan 02 '17 at 17:24
1

The issue here is that Scala thinks you're trying to pass a function "(something)+1" to the println method rather than passing it to the foreach method.

Doing just "println(_)" works because in this case you're not passing a function to println. Instead you're defining a partial application of println. The partial application is a function and can be passed to foreach.

This will work for you:

alist.map(_+1).foreach(println)
Willis Blackburn
  • 8,068
  • 19
  • 36
1

Using the Placeholder Syntax for Anonymous Functions in Scala is a bit tricky. The language specification says:

An expression e of syntactic category Expr binds an underscore section u, if the following two conditions hold: (1) e properly contains u, and (2) there is no other expression of syntactic category Expr which is properly contained in e and which itself properly contains u.

The bold text establishes how the Scala compiler determines which expression is the anonymous functions created with the placeholder operator - it is always the innermost expression, which properly contains the _ operator. In the case of alist.foreach(println(_+1)), the expression that binds the underscore is _ + 1. It is not bound by the entire println(_ + 1) expression since _ + 1 is properly contained in println(_ + 1). As already written in the other answers, in that case you must use the explicit syntax for anonymous functions:

alist.foreach(x => println(x + 1))

For the sake of completeness: alist.foreach(println(_+1)) translates to alist.foreach(println(x => x + 1)). Since println takes arguments of various kinds, the compiler is not able to infer uniquely a type for x and hence the missing parameter type error in that case. Even if you were to give x a type, another error will ensue since foreach expects a function that takes one argument of the elemental type of alist.

Hristo Iliev
  • 72,659
  • 12
  • 135
  • 186