Reputation: 1499
I'm trying to understand for comprehensions in Scala, and I have a lot of examples that I sort of understand...
One thing I'm having a hard time figuring out is for ( ) vs for { }. I've tried both, and it seems like I can do one thing in one but it breaks in the other.
For example, this does NOT work:
def encode(number: String): Set[List[String]] =
if (number.isEmpty) Set(List())
else {
for (
split <- 1 to number.length
word <- wordsForNum(number take split)
rest <- encode(number drop split)
) yield word :: rest
}.toSet
However, if you change it to { }, it does compile:
def encode(number: String): Set[List[String]] =
if (number.isEmpty) Set(List())
else {
for {
split <- 1 to number.length
word <- wordsForNum(number take split)
rest <- encode(number drop split)
} yield word :: rest
}.toSet
These examples are from a Coursera class I'm taking. The professor didn't mention the "why" in the video & I was wondering if anyone else knows.
Thanks!
Upvotes: 7
Views: 1246
Reputation: 39577
From the syntax in the spec, it might seem that parens and braces are interchangeable:
but because the generators are separated by semis, the following rules kick in:
http://www.scala-lang.org/files/archive/spec/2.11/01-lexical-syntax.html#newline-characters
I have read and understood that section in the past, from which I vaguely recall the gist that newlines are enabled in the braces, which is to say, a newline char is taken as nl
which serves as a semi
.
So you can put the generators on separate lines instead of using semicolons.
This is the usual "semicolon inference" that lets you not write semicolons as statement terminators. So the newline in the middle of the generator is not taken as a semi, for instance:
scala> for (c <-
| List(1,2,3)
| ) yield c+1
res0: List[Int] = List(2, 3, 4)
scala> for { c <-
| List(1,2,3)
| i = c+1
| } yield i
res1: List[Int] = List(2, 3, 4)
Upvotes: 8
Reputation: 1171
In Scala () are usually for when you only have one statement. Something like this would have worked:
def encode(number: String): Set[Int] =
if (number.isEmpty) Set()
else {
for (
split <- 1 to number.length // Only one statement in the comprehension
) split
}.toSet
Add one more and it would fail to compile. The same is true for map for example
OK
List(1,2,3).map(number =>
number.toString
)
Not OK (have to use curly braces)
List(1,2,3).map(number =>
println("Hello world")
number.toString
)
Why that is. I have no idea :)
Upvotes: 4