Список опций: эквивалент последовательности в Scala? - PullRequest
14 голосов
/ 19 июля 2011

Что является эквивалентом sequence Хаскелла в Scala?Я хочу превратить список опций в опцию списка.Он должен выглядеть как None, если любой из параметров None.

List(Some(1), None, Some(2)).???     --> None
List(Some(1), Some(2), Some(3)).???  --> Some(List(1, 2, 3))

Ответы [ 7 ]

24 голосов
/ 19 июля 2011

Scalaz определяет последовательность .

Вот пример:

scala> import scalaz._
import scalaz._

scala> import Scalaz._
import Scalaz._

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

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

Обратите внимание, что во втором примере вы должны использовать некоторую функцию Scalaz для создания Some.- иначе, список создается как List [Some [Int]], что приводит к этой ошибке:

scala> List(Some(1), Some(2), Some(3)).sequence
<console>:14: error: could not find implicit value for parameter n: scalaz.Applicative[N]
       List(Some(1), Some(2), Some(3)).sequence

Функции Scalaz some (a) и none создают значения Some и None типа Option [A].

16 голосов
/ 19 июля 2011

Если вам нужно решение только для List и Option, а не для общей монады, тогда следующие действия сделают следующее:

def sequence[T](l : List[Option[T]]) = 
  if (l.contains(None)) None else Some(l.flatten)

REPL сеанс,

scala> sequence(List(Some(1), None, Some(2)))
res2: Option[List[Int]] = None

scala> sequence(List(Some(1), Some(2), Some(3)))
res3: Option[List[Int]] = Some(List(1, 2, 3)) 

Обновление 20/8 /2014

Просто используйте Scalaz ...

4 голосов
/ 19 июля 2011

Здесь та же самая функция, что и выше, использующая комбинацию foldRight и map / flatmap, которая должна проходить список только один раз:

  def sequence[A](lo: List[Option[A]]): Option[List[A]] = 
    lo.foldRight (Option(List[A]())) { (opt, ol) => 
      ol flatMap (l => opt map (o => o::l))
    }

Или, если вы предпочитаете версию для понимания:

  def sequence2[A](lo: List[Option[A]]): Option[List[A]] = 
    lo.foldRight (Option(List[A]())) { (opt, ol) =>
      for {l <- ol; o <- opt} yield (o::l)
    }
2 голосов
/ 19 июля 2011

Прежде всего, я рекомендую вам ознакомиться с документами API для Списка .

Что касается решения, это может быть не самый изящный способ сделать это, но это 'сработает (и без внешних зависимостей):

// a function that checks if an option is a None
def isNone(opt:Option[_]) = opt match {
  case None => true
  case _ => false
}

//templated for type T so you can use whatever Options
def optionifyList[T](list:List[Option[T]]) = list.exists(isNone) match {
  case true => None
  case false => Some(list.flatten)
}

И тест просто для уверенности ...

scala> val hasNone = Some(1) :: None :: Some(2) :: Nil
hasNone: List[Option[Int]] = List(Some(1), None, Some(2))

scala> val hasSome = Some(1) :: Some(2) :: Some(3) :: Nil
hasSome: List[Some[Int]] = List(Some(1), Some(2), Some(3))

scala> optionifyList(hasSome)
res2: Option[List[Int]] = Some(List(1, 2, 3))

scala> optionifyList(hasNone)
res3: Option[List[Int]] = None
0 голосов
/ 24 марта 2017

Может быть, это поможет, поскольку он проходит только один раз и использует рекурсию

def sequence[A](a: List[Option[A]]): Option[List[A]] =
a match {
  case Nil => Some(Nil)
  case h :: rest => h.flatMap(x => sequence(rest).map(x :: _))
}
0 голосов
/ 25 июня 2015

Так как вам все равно нужно сплющить, просто сделайте это сначала ...

def sequence(lo: List[Option[A]]): Option[List[A]] = lo.flatten match {
    la: List[A] if(la.length == lo.length) => Some(la)
    _ => None
}

рекурсия хвоста может быть самой быстрой

0 голосов
/ 06 апреля 2015

Это очень просто для понимания:

val x : Option[String] = Option("x")
val y : Option[String] = Option("y")
val z : Option[String] = None

// Result -> a: Option[List[String]] = None    
val a = for {
  x <- x
  y <- y
  z <- z
} yield List(x,y,z)    

// Result -> b: Option[List[String]] = Some(List(x, y))    
val b = for {
  x <- x
  y <- y
} yield List(x,y)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...