选项列表:相当于Scala中的序列?

时间:2011-07-19 16:27:18

标签: scala haskell sequence

Scala中Haskell的sequence相当于什么?我想将选项列表转换为列表选项。如果任何选项为None,则结果应为None

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

7 个答案:

答案 0 :(得分:24)

Scalaz定义sequence

以下是一个例子:

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将构造为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函数创建Option [A]类型的Some和None值。

答案 1 :(得分:16)

如果你想要一个只有List和Option的解决方案,而不是一般的monad,那么下面就可以完成这项工作,

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)) 

2014年8月8日更新

只需使用Scalaz ......

答案 2 :(得分:4)

以下是使用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)
    }

答案 3 :(得分:2)

首先,我建议您查看API docs for List

至于解决方案,这可能不是最优雅的方式,但它可以工作(并且没有外部依赖):

// 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

答案 4 :(得分:0)

这是非常简单的理解:

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)

答案 5 :(得分:0)

既然你需要扁平化,那就先做吧......

rhs

尾递归可能是最快的

答案 6 :(得分:0)

也许这会有所帮助,因为它只遍历一次并使用递归

(ngModelChange)