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.
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)(_))