Подтвердить что ты не робот

Как преобразовать A [B [C]] в B [A [C]], если A и B являются монадами?

Я ищу более общее решение, которое использует монад (и, возможно, моноиды), чтобы достичь того же, что и if( xs.contains(None) ) None else Some(xs.flatten) для xs для типа Seq[Option[A]].

Как я могу сделать это с помощью Scalaz? Я чувствую, что мне не хватает чего-то очевидного.

4b9b3361

Ответ 1

Недостаточно наличия двух монад (для M) и более чем достаточно (для N) - это, конечно, не достаточно, но если M имеет экземпляр Traverse и N имеет экземпляр Applicative, вы можете использовать sequence. Например:

import scalaz._, Scalaz._

def foo[A](xs: List[Option[A]]): Option[List[A]] = xs.sequence

Это семантика, которую вы хотите. Обратите внимание, что я использую List вместо Seq, так как Scalaz 7 больше не предоставляет необходимый экземпляр Traverse для Seq (хотя вы можете легко написать свой собственный).


Как вы заметили, следующее не будет компилироваться:

List(Some(1), Some(45)).sequence

Хотя это прекрасно, если вы выбрали None там:

scala> List(Some(1), None, Some(45)).sequence
res0: Option[List[Int]] = None

Это потому, что выводимый тип List(Some(1), Some(45)) будет List[Some[Int]], и у нас нет экземпляра Applicative для Some.

Scalaz предлагает удобный Some метод, который работает как Some.apply, но дает вам то, что уже было напечатано как Option, поэтому вы можете написать следующее:

scala> List(some(1), some(45)).sequence
res1: Option[List[Int]] = Some(List(1, 45))

Не требуется дополнительная набрав.