如何使用 orElse 组合返回 Option 的函数?
How to compose functions returning Option with orElse?
假设我有两个函数 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 派对库。
据我所知,标准库中没有这样的东西,但您可以使用 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)
您可以使用来自 scalaz 的 Semigroup
类型类的组合操作 (|+|
)。
Option
的默认半群使用内容的半群,如果两个值都存在,则合并这些值。
因此,要模仿 orElse
行为,您需要将 Option
包装在 Tags.FirstVal
标记中。
Tags.FirstVal
的文档指出:
Type tag to choose a scalaz.Semigroup
instance that selects the first operand to append.
您可以使用 Tag
的 .subst
和 .unsubst
方法从某些 F[T]
中包装和解包类型 T
。在我看来,您还必须在类型推断方面帮助 Scala。
总而言之,组合函数如下所示:
type F[T] = Int => Option[T]
val f = Tags.FirstVal.unsubst(
Tags.FirstVal.subst[F, Int](foo) |+|
Tags.FirstVal.subst[F, Int](bar))
要将它与 flatMap
一起使用,您必须以某种方式使用从 Option
到 List
的隐式转换。所以 flatMap
调用可能如下所示:
xs flatMap (f(_))
如果覆盖 Option
的隐式 Monoid
实例,您还可以使 |+|
像 orElse
一样工作:
import scalaz._, Scalaz._
implicit val inst: Monoid[Option[Int]] =
Tags.First.unsubst(scalaz.std.option.optionFirst[Int])
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 |+| bar)(_))
假设我有两个函数 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 派对库。
据我所知,标准库中没有这样的东西,但您可以使用 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)
您可以使用来自 scalaz 的 Semigroup
类型类的组合操作 (|+|
)。
Option
的默认半群使用内容的半群,如果两个值都存在,则合并这些值。
因此,要模仿 orElse
行为,您需要将 Option
包装在 Tags.FirstVal
标记中。
Tags.FirstVal
的文档指出:
Type tag to choose a
scalaz.Semigroup
instance that selects the first operand to append.
您可以使用 Tag
的 .subst
和 .unsubst
方法从某些 F[T]
中包装和解包类型 T
。在我看来,您还必须在类型推断方面帮助 Scala。
总而言之,组合函数如下所示:
type F[T] = Int => Option[T]
val f = Tags.FirstVal.unsubst(
Tags.FirstVal.subst[F, Int](foo) |+|
Tags.FirstVal.subst[F, Int](bar))
要将它与 flatMap
一起使用,您必须以某种方式使用从 Option
到 List
的隐式转换。所以 flatMap
调用可能如下所示:
xs flatMap (f(_))
如果覆盖 Option
的隐式 Monoid
实例,您还可以使 |+|
像 orElse
一样工作:
import scalaz._, Scalaz._
implicit val inst: Monoid[Option[Int]] =
Tags.First.unsubst(scalaz.std.option.optionFirst[Int])
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 |+| bar)(_))