Хотя Applicative[Option]
в Scalaz имеет неправильное поведение для непосредственного использования MA#sequence
, вы также можете получить Applicative
из Monoid
. Это удобно с MA#foldMapDefault
или MA#collapse
.
В этом случае мы используем Monoid[Option[List[Int]]
. Сначала мы выполняем внутреннюю карту (MA#∘∘
), чтобы обернуть отдельные Int
s в List
s одного элемента.
(List(some(1), none[Int], some(2)) ∘∘ {(i: Int) => List(i)}).collapse assert_≟ some(List(1, 2))
(List(none[Int]) ∘∘ {(i: Int) => List(i)}).collapse assert_≟ none[List[Int]]
(List[Option[Int]]() ∘∘ {(i: Int) => List(i)}).collapse assert_≟ none[List[Int]]
Абстрагирование от List
до любого контейнера с экземплярами для Traverse
, Pointed
и Monoid
:
def co2oc[C[_], A](cs: C[Option[A]])
(implicit ct: Traverse[C], cp: Pointed[C], cam: Monoid[C[A]]): Option[C[A]] =
(cs ∘∘ {(_: A).pure[C]}).collapse
co2oc(List(some(1), none[Int], some(2))) assert_≟ some(List(1, 2))
co2oc(Stream(some(1), none[Int], some(2))) assert_≟ some(Stream(1, 2))
co2oc(List(none[Int])) assert_≟ none[List[Int]]
co2oc(List[Option[Int]]()) assert_≟ none[List[Int]]
К сожалению, попытка скомпилировать этот код в настоящее время либо вызывает # 2741 , либо отправляет компилятор в бесконечный цикл.
UPDATE
Чтобы избежать обхода списка дважды, я должен был использовать foldMapDefault
:
(List(some(1), none[Int], some(2)) foldMapDefault (_ ∘ ((_: Int).pure[List])))
Этот ответ был основан на исходном запросе о том, что пустой список или список, содержащий только None
s, должен возвращать None
. Между прочим, это лучше всего смоделировать с помощью типа Option[scalaz.NonEmptyList]
- NonEmptyList
, который гарантирует хотя бы один элемент.
Если вы просто хотите List[Int]
, есть много более простых способов, приведенных в других ответах. Два прямых способа, которые не были упомянуты:
list collect { case Some(x) => x }
list flatten