Question

The Learn You a Haskell tutorial has an example of using a let binder in a list comprehension:

calcBmis xs = [bmi | (w, h) <- xs, let bmi = w / h ^ 2, bmi >= 25.0]

The function takes a list of height/weight pairs, and returns a list of the corresponding body-mass indices that exceed some limit, eg:

ghci> calcBmis [(70, 1.85), (50, 2.00), (130, 1.62)]
[49.53513183965858]

What's interesting to me here is that the value bmi that is bound within the comprehension can be used both in a guard and in the resulting expression. The only way I know how to do something similar in Scala is to write:

def calcBmis(xs : Seq[(Double,Double)]) =
  for((w,h) <- xs ; bmi <- Some(w / (h*h)) if bmi >= 25.0) yield bmi

Having to wrap my value in a Some here feels wrong. Anyone knows of a better way?

Was it helpful?

Solution

Yes, there is such syntax.

def calcBmis(xs : Seq[(Double,Double)]) =
  for((w,h) <- xs ; bmi = w / (h*h); if bmi >= 25.0) yield bmi

One-liner alternative (but not comprehension):

calcBmis.map(wh => wh._1/(wh._2*wh._2)).filter(_>=25.0)

OTHER TIPS

I've just copied om-nom-nom's answer to show how you can lay it out using curly braces without the semicolons; it's a bit clearer this way

def calcBmis(xs : Seq[(Double,Double)]) = for { (w,h) <- xs 
                                                bmi = w / (h*h)
                                                if bmi >= 25.0 } yield bmi

and instead of using tuples, I'd use a case expression (again, requires curly braces)

xs map {case (w, h) => w / (h * h)} filter {_ >= 25.0}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top