Reputation: 42050
Suppose I have two functions foo: Int => Option[Int]
and bar: Int => Option[Int]
and use them to process a list:
val xs: List[Int] = ...
xs flatMap {x => foo(x) orElse bar(x)}
Can I write xs flatMap (foo orElse bar)
instead of {x => foo(x) orElse bar(x)}
?
I can use a 3d party library.
Upvotes: 3
Views: 581
Reputation: 14224
You may use the combine operation (|+|
) of the Semigroup
typeclass from scalaz.
The default semigroup of Option
uses the semigroup of the content and combines the values if both values are present.
So to imitate the orElse
behaviour, you would need to wrap the Option
s in the Tags.FirstVal
tag.
The documentation for Tags.FirstVal
states:
Type tag to choose a
scalaz.Semigroup
instance that selects the first operand to append.
You can use .subst
and .unsubst
methods of the Tag
, to wrap and unwrap a type T
from inside some F[T]
. It also seems to me that you'd have to help Scala a bit with type inference.
All in all the combined function looks like this:
type F[T] = Int => Option[T]
val f = Tags.FirstVal.unsubst(
Tags.FirstVal.subst[F, Int](foo) |+|
Tags.FirstVal.subst[F, Int](bar))
And to use it with flatMap
, you have to use the implicit conversion from to Option
to List
in some way. So the flatMap
call may look like this:
xs flatMap (f(_))
You can also make the |+|
work as orElse
if you override the implicit Monoid
instance for Option
:
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)(_))
Upvotes: 1
Reputation: 206776
As far as I know something like this is not available in the standard library, but you can add it yourself using an implicit class:
implicit class WithOrElse[T, R](f: T => Option[R]) {
def orElse(g: T => Option[R])(x: T) = f(x) orElse g(x)
}
Example:
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)
Upvotes: 6