views:

368

answers:

5

What I'm looking for is this function:

def maybe[A, B](a: Option[A])(f: A => B)(g: () => B): B = a match 
{
    case Some(x) => f(x)
    case None => g()
}

It's in the Haskell prelude so I'm thinking it might be in the Scala standard library somewhere and I've just missed it. I hate having to recode it in projects so I'm wondering if anyone knows where it is, or if it's definitively not there. Or is there a better method for getting this functionality?

+10  A: 

You could do

val opt:Option[A] = // ...
val result:B = opt.map(a => f(a)).getOrElse(g());

getOrElse takes a by-name parameter, so g will only be evaluated if opt is None.

Ben Lings
Why `a => f(a)` instead of just `f`?
Alexey Romanov
Well, actually, just f ought to work.
Daniel
A: 

I don't think there is. The best I could come up with is to chain Option's "map" and "getOrElse" together:

scala> var a: Option[String] = Some("hello")
a: Option[String] = Some(hello)

scala> a.map(_.toUpperCase).getOrElse("empty") 
res19: java.lang.String = HELLO

scala> a = None
a: Option[String] = None

scala> a.map(_.toUpperCase).getOrElse("empty")
res21: java.lang.String = empty
Walter Chang
A: 

I don't think there is. However, I'd write it to take g by name:

def maybe[A, B](a: Option[A])(f: A => B)(g: => B): B = a.map(f).getOrElse(g)

This is more Scala- and Haskell-like and a bit nicer to use.

Alexey Romanov
+8  A: 

Other answers have given the map + getOrElse composition. Just for the record, you can "add" a maybe function to Option in the following way:

implicit def optionWithMaybe[A](opt: Option[A]) = new {
  def maybe[B](f: A=>B)(g: =>B) = opt map f getOrElse g
}

It's worth noting that the syntax of higher-order functions in Scala is usually nicer when the function parameter comes last. Thus, a better way to organize maybe would be as follows:

def maybe[B](g: =>B)(f: A=>B) = opt map f getOrElse g

This could be used as follows:

val opt: Option[String] = ...
opt.maybe("") { _.toUpperCase }
Daniel Spiewak
+3  A: 

The method would be called fold if it were to adhere to convention (see Either.fold which is the catamorphism for Either).