Есть ли что-то вроде функции Haskell, возможно, встроенной в Scala?

Я ищу эту функцию:

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

Это в прелюдии Haskell, поэтому я думаю, что это может быть в стандартной библиотеке Scala где-то, и я только что пропустил ее. Мне не нравится перекодировать его в проектах, поэтому мне интересно, знает ли кто-нибудь, где он находится, или если он окончательно не существует. Или есть лучший способ получить эту функциональность?

Ответы

Ответ 1

Вы могли бы сделать

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

getOrElse принимает параметр by-name, поэтому g будет оцениваться только, если opt - None.

Ответ 2

Другие ответы дали композицию map + getOrElse. Для записи вы можете "добавить" функцию maybe в Option следующим образом:

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

Стоит отметить, что синтаксис функций более высокого порядка в Scala обычно лучше, когда параметр функции приходит последним. Таким образом, лучший способ организовать maybe будет следующим:

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

Это можно использовать следующим образом:

val opt: Option[String] = ...
opt.maybe("") { _.toUpperCase }

Ответ 3

Метод будет называться fold, если он должен придерживаться соглашения (см. Either.fold, который является катаморфизмом для Либо).

Ответ 4

Вы можете использовать scalaz, а затем у вас есть неявное преобразование в OptionW, у которого есть fold, или вы можете использовать Scala 2.10.0-M3 и использовать встроенный Option.fold

scala> Some(1).fold(5)(_ * 2)
res5: Int = 2

scala> (None: Option[Int]).fold(5)(_ * 2)
res7: Int = 5

Обратите внимание, что сигнатура foldal foldal имеет значение fold[X](some: A => X, none: => X), а встроенное значение fold[X](none: => X)(some: A => X).

Ответ 5

Я не думаю, что есть. Лучшее, что я мог придумать, это объединить опции "карта" и "getOrElse" вместе:

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

Ответ 6

Я не думаю, что есть. Однако я бы написал его, чтобы взять g по имени:

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

Это больше Scala - и Haskell-like и немного приятнее в использовании.

Ответ 7

Я бы использовал Option.fold для этого:

opt.fold(g)(f)

Обратите внимание, что g - это имя, как и getOrElse. Также обратите внимание на инверсию случаев.