1

I successfully implemented the following curried function using flatMap:

  def map3(a: Option[Int], b: Option[Int], c: Option[Int])
(f: (Int, Int, Int) => Option[Int]): Option[Int] = {
    a.flatMap(x => b.flatMap(y => c.flatMap(z => f(x,y,z) ) ) )
  }

Example:

scala> map3(Some(1), Some(2), Some(3))( (x,y,z) => Some(x*y*z) )
res0: Option[Int] = Some(6)

However, when I tried to implement the same function with a for expression:

  def map3ForExpr(a: Option[Int], b: Option[Int], c: Option[Int])
(f: (Int, Int, Int) => Option[Int]): Option[Int] = {
    for { 
        x <- a
        y <- b
        z <- b
        f(x,y,z)
    }
  }  

... the following compile-time error occurred:

C:\Users\Kevin\Workspace\side-work>scalac TestForComprehensionMap3.scala TestForComprehensionMap3.scala:13: error: '<-' expected but '}' found. } ^

Based on reading this excellent post, it seems to me that my map3ForExpr is equivalent to my map3 code.

Please let me know what I'm doing wrong.

Community
  • 1
  • 1
Kevin Meredith
  • 41,036
  • 63
  • 209
  • 384

1 Answers1

2

Kevin, you have to return something from the for-comprehension:

 for{
   x <- a
   y <- b
   z <- c
   out <- f(x, y, z)
 } yield out

That is, it needs to know what to map and flatMap over plus it needs a yeild expression to be able to return a value. Without the yield you'll wind up with a desugared foreach.

Also, to add that if you were to merely yield the f(x, y, z) instead of first unpacking it into out that you'd wind up with an Option[Option[Int]] which is not what you want.

wheaties
  • 35,646
  • 15
  • 94
  • 131
  • 1
    @KevinMeredith More importantly, after reading that post you linked (very good post) and then looking at what I wrote, you understand why. – wheaties Jan 06 '14 at 14:31
  • shouldn't that excellent post's `for-expression`, bullet point #1 be modified to include a `yield`? Example: `for { bound <- list out <- f(bound) } yield out` – Kevin Meredith Jan 06 '14 at 14:49
  • @KevinMeredith Hmm, let me check. If they're just using it for side-effects, no. If not, then it does need to be. – wheaties Jan 06 '14 at 14:53
  • I asked my above question since the post lists `for { bound <- list; f(bound) }` as being equivalent to `list flatMap f`. [I'm aware you're looking into it, but I wanted to mention my reasoning] – Kevin Meredith Jan 06 '14 at 15:03
  • @KevinMeredith I fixed the other post. It had an error just where you said. – wheaties Jan 06 '14 at 15:06