Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

The following code has a lot of conditionals. I am trying to write it in a functional programming way.

val basePrice = {
  var b = 0.0

  if (runtime > 120)
    b += 1.5
  if ((day == Sat) || (day == Sun))
    b += 1.5
  if (!isParquet)
    b += 2
  if (is3D)
    b += 3
  b
}

I think the following code would be a good approach, but maybe I am complicating this too much.

val basePrice = {
  List((runtime > 120, 1.5), 
       (day == Sat || day == Sun, 1.5),
       (!isParquet, 2.0),
       (is3D, 3.0)).foldLeft(0.0)((acum, cond) =>
     if (cond._1) acum + cond._2 else acum)
}

How would you write the first snippet of code using functional programming?

Thanks

share|improve this question

2 Answers

up vote 4 down vote accepted

Each condition is a function. It might be that you could write it more concisely, but I think the code is clearer if you do this:

def priceFunction(cond: => Boolean)(mod: Double => Double) = (_: Double) match {
    case x if cond => mod(x)
    case y => y
}

val modRuntime = priceFunction(runtime > 120)(_ + 1.5)
val modWeekend = priceFunction(day == Sat || day == Sun)(_ + 1.5)
val modParquet = priceFunction(!isParquet)(_ + 2.0)
val mod3d = priceFunction(is3D)(_ + 3.0)
val modifiers = List(
    modRuntime,
    modWeekend,
    modParquet,
    mod3d
)
val modifierFunction = modifiers reduceLeft (_ andThen _)                   

val basePrice = modifierFunction(0.0)

The name of the identifiers here suck, and I could have written val modifiers = modRuntime andThen modWeekend andThen modParquet andThen mod3d without trouble. I choose putting them in a List because it shows how well it can scale.

One could also make PartialFunction and chain them with orElse, for the cases where you want only the first condition.

You see this kind of thing used in web frameworks, such as BlueEyes, Lift or Unfiltered, for example.

share|improve this answer

Maybe a little bit more readable:

val basePrice = List((runtime > 120, 1.5), 
       (day == Sat || day == Sun, 1.5),
       (!isParquet, 2.0),
       (is3D, 3.0)).collect{case (true, b) => b}.sum
share|improve this answer
Scala noob here. Would this cause the list to be traversed twice? One for collect and another for sum? Or scala is aware of that and chains it properly? – simao Aug 17 '11 at 23:24
I think it would be traversed twice, but I really hope you don't want to chain hundreds of these... – Landei Aug 18 '11 at 6:46
Note that you can use .view on lists to make them lazy (and, hence, traversed once). – Nicolas Payette Sep 14 '11 at 5:02

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.