组合Scala选项[Iterable[]]

组合Scala选项[Iterable[]],scala,collections,monads,Scala,Collections,Monads,我正在尝试将两个选项[Iterable[\u]]组合成一个新的选项[Iterable[\u]]。如果其中一个(或两个)元素是Some,我想返回Some,否则返回None。似乎应该有一种惯用的方法来做这件事,但我似乎找不到。下面的内容似乎满足了我的要求,但并不是我所希望的圆滑的解决方案 def merge( i1: Option[Iterable[_]], i2: Option[Iterable[_]] ): Option[Iterable[_]] = (i1, i2) match {

我正在尝试将两个
选项[Iterable[\u]]
组合成一个新的
选项[Iterable[\u]]
。如果其中一个(或两个)元素是Some,我想返回Some,否则返回None。似乎应该有一种惯用的方法来做这件事,但我似乎找不到。下面的内容似乎满足了我的要求,但并不是我所希望的圆滑的解决方案

def merge(
    i1: Option[Iterable[_]], i2: Option[Iterable[_]]
): Option[Iterable[_]] = (i1, i2) match {
   case (Some(as), Some(bs)) => Some(as ++ bs)
   case (a @ Some(as), None) => a
   case (None, b @ Some(bs)) => b
   case _ => None
}
任何提示都将不胜感激。谢谢

这是有效的:

def merge(i1: Option[Iterable[_]], i2: Option[Iterable[_]]): Option[Iterable[_]] =
  (for (a <- i1; b <- i2) yield a ++ b).orElse(i1).orElse(i2)

如果你愿意接受一点抽象代数,这里有一个很好的概括:
Iterable[\u]
是一个欠串联,其中幺半群只是一组东西(在本例中是Iterable集合)和一个类似加法的操作(串联),带有一些简单的属性和一个标识元素(空集合)

类似地,如果
A
是一个幺半群,那么
选项[A]
也是您的
合并
的更一般版本下的一个幺半群:

Some(xs) + Some(ys) == Some(xs + ys)
Some(xs) + None     == Some(xs)
None     + Some(ys) == Some(ys)
None     + None     == None
(注意,
A
是一个幺半群,我们需要知道在第一行要做什么。)

在其
Monoid
type类中捕获所有这些泛化,您可以这样编写
merge

import scalaz._, Scalaz._

def merge(i1: Option[Iterable[_]], i2: Option[Iterable[_]]) = i1 |+| i2
其工作原理与预期一致:

scala> merge(Some(1 to 5), None)
res0: Option[Iterable[_]] = Some(Range(1, 2, 3, 4, 5))

scala> merge(Some(1 to 5), Some(4 :: 3 :: 2 :: 1 :: Nil))
res1: Option[Iterable[_]] = Some(Vector(1, 2, 3, 4, 5, 4, 3, 2, 1))

scala> merge(None, None)
res2: Option[Iterable[_]] = None

(请注意,还有其他操作可以为
Iterable
Option
提供有效的
Monoid
实例,但您的操作是最常用的,也是Scalaz默认提供的操作。)

您可以将其用于任意算术:

def merge(xs: Option[Iterable[_]]*) = 
  if (xs.forall(_.isEmpty)) None else Some(xs.flatten.flatten)

类似的问题:,可能会有帮助
def merge(xs: Option[Iterable[_]]*) = 
  if (xs.forall(_.isEmpty)) None else Some(xs.flatten.flatten)