这里有一个可能性:
import scala.annotation.tailrec
def sequence[A](a: List[Option[A]]): Option[List[A]] = {
@tailrec
def seq(remaining: List[Option[A]], result: Option[List[A]]): Option[List[A]] = {
if (remaining.isEmpty) {
result
} else {
(remaining.head, result) match {
case (Some(item), Some(list)) => seq(remaining.tail, Some(item :: list))
case _ => None
}
}
}
seq(a, Some(Nil))
}
,因为它击中了第一None
元素,它会很快停止评估名单。并且应该返回与实现相同的结果。但是,注意这个实现对于空输入列表将返回Some(Nil)非常重要。
的实施可以缩短一点,这取决于你对表现和其他可读性标准的偏好:
def sequence[A](a: List[Option[A]]): Option[List[A]] = {
@tailrec
def seq(remaining: List[Option[A]], result: Option[List[A]]): Option[List[A]] = {
(remaining, result) match {
case (Nil, _) => result
case (Some(item) :: tail, Some(list)) => seq(tail, Some(item :: list))
case _ => None
}
}
seq(a, Some(Nil))
}
结果将Some
单子或None
。如果您想保留列表顺序,你将不得不
- 取代
seq(a, Some(Nil))
与seq(a, Some(Nil)).map(_.reverse)
- 或
list :+ item
更换item :: list
。
虽然,list :+ item
不追加项目的List
的最佳方式。如果您想保留订单并使用'@tailrec'方法,我建议您使用Vector
作为结果类型,而不是List
。
您对结果缺少'.map(_。reverse)'。你也可以将两个'None'匹配情况合并为_ _> None,并将它们放在'Some'情况之后。 – Arjan
编辑我的答案与关于列表顺序的评论。然而,如果我申请你的第二个建议,我不得不放弃'@ tailrec',would'nt I. –
不,要成为尾部递归,recusrive调用不必在最新的匹配语句中,只是该特定情况下的最后一项陈述。 – Arjan