Ответ 1
Обзор этого ответа:
- Однослойное решение с использованием
fold
- Маленькая демонстрация со
fold
- Обсуждение того, почему
fold
-solution может быть таким же "очевидным", какif-else
-solution.
Решение
Вы всегда можете использовать fold
для преобразования Option[A]
во все, что вы хотите:
a.fold(Option(makeB())){_ => Option.empty[B]}
демонстрация
Ниже приведен полный пример со всеми необходимыми определениями типов:
class A
class B
def makeB(): B = new B
def foo(a: Option[A]): Option[B] = a match {
case Some(_) => None
case None => Some(makeB())
}
def foo2(a: Option[A]): Option[B] =
a.fold(Option(makeB())){_ => Option.empty[B]}
println(foo(Some(new A)))
println(foo(None))
println(foo2(Some(new A)))
println(foo2(None))
Эти результаты:
None
Some([email protected])
None
Some([email protected])
Почему fold
кажется менее интуитивным
В комментариях @TheArchetypalPaul прокомментировал, что fold
кажутся "намного менее очевидными", чем решение if-else
.
Я бы сказал, что это в основном артефакт, вызванный наличием специального if-else
синтаксиса для булевых.
Если бы что-то вроде стандартного
def ifNone[A, B](opt: Option[A])(e: => B) = new {
def otherwise[C >: B](f: A => C): C = opt.fold((e: C))(f)
}
синтаксис, который можно использовать следующим образом:
val optStr: Option[String] = Some("hello")
val reversed = ifNone(optStr) {
Some("makeB")
} otherwise {
str => None
}
и, что более важно, если бы этот синтаксис был упомянут на первой странице каждого введения на каждый язык программирования, изобретенный за последние полвека, тогда решение ifNone-otherwise
(то есть fold
) выглядело бы намного более естественным для большинства людей,
Действительно, метод Option.fold
является устранителем типа Option[T]
: всякий раз, когда у нас есть Option[T]
и вы хотите получить A
из нее, наиболее очевидной ожидаемой задачей должно быть fold(a)(b)
с a: A
и b: T => A
В отличие от специальной обработки булевых элементов с if-else
-syntax (что является простым соглашением) метод fold
является очень фундаментальным, тот факт, что он должен быть там, может быть получен из первых принципов.