0

While reviewing the code for the water pouring problem in the Coursera Scala class, I came across two uses of map where I don't understand the syntax.

I'm used to:

a.map(b => b * b)

But I'm seeing:

a map something

For example:

next <- moves map path.extend

does this mean "for each next in moves, path.extend(next)"?

paths #:: from(more, explored ++ (more map (_.endstate)))

does this mean "add the endstate of more to explored"?

1
  • 1
    Scala syntax allows the standard method invocation obj.meth(arg) to be expressed with spaces obj meth arg. Commented Nov 3, 2015 at 19:12

2 Answers 2

6

In scala, the following expressions are equivalent:

moves map path.extend
moves map(path.extend)
moves.map(path.extend)
moves.map(m => path.extend(m))

And the following are equivalent:

more map (_.endstate)
more.map(_.endstate)
more.map(m => m.endstate)
Sign up to request clarification or add additional context in comments.

1 Comment

moves.map(path.extend) and moves.map(m => path.extend(m)) are not equivalent: def a(x: Int)(y: Int) = x + y; List(1).map(a); List(1).map(x => a(x)) (last statement won't compile)
1

To answer your first question, I think you're correct about next <- moves map path.extend

I'm assuming you're talking about a "for comprehension". For example,

val a = List (1, 3, 5)

a.map(b => b * b)
  //> res0: List[Int] = List(1, 9, 25)

for {
  blah <- a map (b => b * b)
} yield blah  
  //> res1: List[Int] = List(1, 9, 25)

You can see these two return the same result and are equivalent in Scala.

So we're saying for every element in "a" call the function (b => b * b).


In your example it's more like this scenario:

case class Song(artists:List[String], title: String)

val songs = List(Song(List("Michael Jackson", "Janet Jackson"), "Scream"),
                             Song(List("Janet"), "Unbreakable"))

for {
  song <- songs
  artist <- song.artists
  if artist startsWith "Mic"
} yield song.title                                
  //> res0: List[String] =     List(Scream)

songs.flatMap(
    song => song.artists.withFilter(artist => artist startsWith "Mic").map(artist => song.title)
)                                                 
  //> res1: List[String] = List(Scream)

You can see these are also equivalent but the "for-comprehension" is easier to read.

2 Comments

Yes! I took that line from this code: def from(paths: Set[Path], explored: Set[State]): Stream[Set[Path]] = if (paths.isEmpty) Stream.empty else { val more = for { path <- paths next <- moves map path.extend if !(explored contains next.endState) } yield next paths #:: from(more, explored ++ (more map (_.endState))) }
In that case I think it's more of a combination of a flatMap and withFilter. I'm adding some new info to the answer above. Hope it helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.