如何用orElse组合返回Option的函数?

时间:2016-06-08 11:06:11

标签: scala pointfree

假设我有两个函数foo: Int => Option[Int]bar: Int => Option[Int]并使用它们来处理列表:

val xs: List[Int] = ...
xs flatMap {x => foo(x) orElse bar(x)}

我可以写xs flatMap (foo orElse bar)代替{x => foo(x) orElse bar(x)}吗? 我可以使用3d派对库。

2 个答案:

答案 0 :(得分:6)

据我所知,标准库中没有此类内容,但您可以使用implicit class自行添加:

implicit class WithOrElse[T, R](f: T => Option[R]) {
  def orElse(g: T => Option[R])(x: T) = f(x) orElse g(x)
}

示例:

val foo: Int => Option[Int] = x => if (x % 2 == 0) Some(x) else None
val bar: Int => Option[Int] = x => if (x % 3 == 0) Some(x) else None

val xs = List(1, 2, 3, 4, 5, 6, 7, 8)

xs flatMap (foo orElse bar)

答案 1 :(得分:1)

您可以使用scalaz中|+|类型类的合并操作(Semigroup)。

Option的默认半群使用内容的半群,如果两个值都存在,则组合这些值。 因此,要模仿orElse行为,您需要将Option包裹在Tags.FirstVal标记中。

Tags.FirstVal州的文档:

  

键入tag以选择一个scalaz.Semigroup实例,该实例选择要追加的第一个操作数。

您可以使用.subst的{​​{1}}和.unsubst方法,从Tag内部包装和解包类型T。在我看来,你必须通过类型推断来帮助Scala。

总而言之,组合功能如下所示:

F[T]

要将其与type F[T] = Int => Option[T] val f = Tags.FirstVal.unsubst( Tags.FirstVal.subst[F, Int](foo) |+| Tags.FirstVal.subst[F, Int](bar)) 一起使用,您必须以某种方式使用从flatMapOption的隐式转换。因此List调用可能如下所示:

flatMap

如果您覆盖xs flatMap (f(_)) 的隐式|+|实例,也可以使orElse工作为Monoid

Option