Ответ 1
Вы могли бы сделать
val opt:Option[A] = // ...
val result:B = opt.map(f).getOrElse(g());
getOrElse
принимает параметр by-name, поэтому g
будет оцениваться только, если opt
- None
.
Я ищу эту функцию:
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 где-то, и я только что пропустил ее. Мне не нравится перекодировать его в проектах, поэтому мне интересно, знает ли кто-нибудь, где он находится, или если он окончательно не существует. Или есть лучший способ получить эту функциональность?
Вы могли бы сделать
val opt:Option[A] = // ...
val result:B = opt.map(f).getOrElse(g());
getOrElse
принимает параметр by-name, поэтому g
будет оцениваться только, если opt
- None
.
Другие ответы дали композицию 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 }
Метод будет называться fold, если он должен придерживаться соглашения (см. Either.fold, который является катаморфизмом для Либо).
Вы можете использовать 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)
.
Я не думаю, что есть. Лучшее, что я мог придумать, это объединить опции "карта" и "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
Я не думаю, что есть. Однако я бы написал его, чтобы взять g
по имени:
def maybe[A, B](a: Option[A])(f: A => B)(g: => B): B = a.map(f).getOrElse(g)
Это больше Scala - и Haskell-like и немного приятнее в использовании.
Я бы использовал Option.fold
для этого:
opt.fold(g)(f)
Обратите внимание, что g
- это имя, как и getOrElse
. Также обратите внимание на инверсию случаев.