Отмена выбора необязательной опции

#scala #join #option #monads #flatten

#scala #монады #сгладить #scala-опция

Вопрос:

Допустим, у меня есть val s: Option[Option[String]] . Таким образом, она может иметь следующие значения:

Some(Some("foo"))
Some(None)
None

Я хочу уменьшить ее так, чтобы первая стала Some("foo") , а две другие стали None . Очевидно, что есть много способов добиться этого, но я ищу простой, возможно, встроенный, менее чем однострочный.

Ответ №1:

Жаль, что flatten этого не существует. Так и должно быть.

Flatten теперь существует.

Как и раньше,

 s getOrElse None
  

(в дополнение к другим ответам) также сделает то же самое.

Комментарии:

1. похоже, что она существует сейчас: scala> Some(Некоторые(1)).сгладить res10: Option[Int] = Some(1)

2. похоже, flatten также внедрил ее в cats

3. @Alexy когда я вызываю flatten такой объект, как Some(Some(Some(1))) , я получаю Cannot prove that Any <:< Option[B]

Ответ №2:

Вы могли бы использовать для этого scalaz join , поскольку это одна из монадических операций:

 doubleOpt.join
  

Вот это в REPL:

 scala> import scalaz._; import Scalaz._
import scalaz._
import Scalaz._

scala> some(some("X")).join
res0: Option[java.lang.String] = Some(X)

scala> some(none[String]).join
res1: Option[String] = None

scala> none[Option[String]].join
res3: Option[String] = None
  

Он доступен для всего, что имеет экземпляр typeclass для монады.

Комментарии:

1. У меня есть такая карта, val map = Map("a"->Some(Some(1)), "b"->2) когда я вызываю map.get("a").join , я вижу could not find implicit value for parameter ev: scalaz.Liskov.<~<[Any,Option[B]]

Ответ №3:

 s.flatten
  

за которым следует набор символов, чтобы довести меня до минимума, который позволяет stackoverflow

Комментарии:

1. Это то, о чем я думаю, но это возвращает Iterable, а не Option.

2. Хм, это очень странно. Зачем им это делать? Вместо этого попробуйте s.flatmap(x=>x).

3. Можно было бы также написать s flatMap identity .

4. Подводя итог вышесказанному: List(Some(Some("foo")), Some(None), None) map { _ flatMap identity } дает List[Option[java.lang.String]] = List(Some(foo), None, None) результат, который, я думаю, и есть то, чего хотел Кнут (OP и первый неполярный медвежонок по имени «Кнут», о котором я слышал).

Ответ №4:

Я думаю, что преобразование в Iterable просто отлично. Используйте эти шаги, чтобы перейти от Option[Option[String] к одному Option[String]

 s.flatten.headOption 
  

(который возвращает Option[String] )

Ответ №5:

Вы могли бы использовать flatMap следующим образом:

 val options = List(Some(Some(1)), Some(None), None)
options map (_ flatMap (a => a))
  

Это приведет к сопоставлению List[Option[Option[Int]]] с List[Option[Int]] .

Если у вас просто есть опция, вы можете использовать ее следующим образом:

 val option = Some(Some(2))
val unzippedOption = option flatMap (b => b)
  

Это приведет к выравниванию вашего Option[Option[Int]] до Option[Int] .

Ответ №6:

Ну, я на самом деле не понимаю, почему это может быть просто None (третий случай). Если это действительно может быть также просто None, то я бы проголосовал за ответ Рекса Керра, иначе было бы достаточно just .get:

 scala> Some(Some("foo")).get
res0: Some[java.lang.String] = Some(foo)

scala> Some(None).get
res1: None.type = None
  

Комментарии:

1. Это может быть, None потому что это Option !

2. Да, но это опция внутри опции … поэтому я бы ожидал, что это Some (Некоторое («что-то»)) для положительного результата и Some (None) для отрицательного результата. Тогда какое третье состояние описывает просто None? Что ж, если проблема заключается в логике трех состояний, только тогда это имеет смысл.

3. Это своего рода эквивалент future: Some(Some(X)) является вычисляемым значением, Some(None) указывает, что future завершилось без значения, и None указывает, что future не вернулся

4. Опция [Строка] является строкой или нет. Давайте запишем это как String 1, что означает, что это может быть любая строка или 1 другая вещь. Тогда параметр [Option[String]] равен (Строка 1) 1 или Строка 2. То есть это строка, или это одна из двух других вещей. Другими словами, параметр[Option[Строка]] изоморфен любому[логическое значение, строка]. Я думаю, что более поздняя структура более четко указывает на то, что либо вычисление успешно приводит к созданию строки, либо может произойти сбой двумя разными способами.

5. Хе-хе, хорошее объяснение — «Есть много способов потерпеть неудачу, но только один для достижения успеха». 🙂