Skip to content

Commit 502f33d

Browse files
authored
Merge pull request #501 from danicheg/or-keep
Add `mapOrKeepIn` / `flatMapOrKeepIn` to `F[Option[A]]` and `F[Either[A,B]]` syntaxes
2 parents 772f5e0 + 44806a0 commit 502f33d

File tree

4 files changed

+36
-0
lines changed

4 files changed

+36
-0
lines changed

shared/src/main/scala/mouse/feither.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ final class FEitherOps[F[_], L, R](private val felr: F[Either[L, R]]) extends An
4848
def flatMapIn[A >: L, B](f: R => Either[A, B])(implicit F: Functor[F]): F[Either[A, B]] =
4949
F.map(felr)(_.flatMap(f))
5050

51+
def flatMapOrKeepIn[A >: L, B >: R](pfa: PartialFunction[R, Either[A, B]])(implicit F: Functor[F]): F[Either[A, B]] =
52+
F.map(felr)(_.flatMap(a => pfa.applyOrElse(a, Right[A, B](_))))
53+
5154
def flatMapF[A >: L, B](f: R => F[Either[A, B]])(implicit F: Monad[F]): F[Either[A, B]] =
5255
F.flatMap(felr) {
5356
case l @ Left(_) => F.pure(l.asInstanceOf[Left[A, B]])
@@ -117,6 +120,9 @@ final class FEitherOps[F[_], L, R](private val felr: F[Either[L, R]]) extends An
117120
def mapIn[A](f: R => A)(implicit F: Functor[F]): F[Either[L, A]] =
118121
F.map(felr)(_.map(f))
119122

123+
def mapOrKeepIn[A >: R](pf: PartialFunction[R, A])(implicit F: Functor[F]): F[Either[L, A]] =
124+
F.map(felr)(_.map(a => pf.applyOrElse(a, identity[A])))
125+
120126
def asIn[B](b: => B)(implicit F: Functor[F]): F[Either[L, B]] =
121127
mapIn(_ => b)
122128

shared/src/main/scala/mouse/foption.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ final class FOptionOps[F[_], A](private val foa: F[Option[A]]) extends AnyVal {
7070
def flatMapIn[B](f: A => Option[B])(implicit F: Functor[F]): F[Option[B]] =
7171
F.map(foa)(_.flatMap(f))
7272

73+
def flatMapOrKeepIn[B >: A](pfa: PartialFunction[A, Option[B]])(implicit F: Functor[F]): F[Option[B]] =
74+
F.map(foa)(_.flatMap(a => pfa.applyOrElse(a, Option[B](_))))
75+
7376
def flatMapF[B](f: A => F[Option[B]])(implicit F: Monad[F]): F[Option[B]] =
7477
F.flatMap(foa)(_.fold(F.pure(Option.empty[B]))(f))
7578

@@ -103,6 +106,9 @@ final class FOptionOps[F[_], A](private val foa: F[Option[A]]) extends AnyVal {
103106
def mapIn[B](f: A => B)(implicit F: Functor[F]): F[Option[B]] =
104107
F.map(foa)(_.map(f))
105108

109+
def mapOrKeepIn[B >: A](pf: PartialFunction[A, B])(implicit F: Functor[F]): F[Option[B]] =
110+
F.map(foa)(_.map(a => pf.applyOrElse(a, identity[B])))
111+
106112
def asIn[B](b: => B)(implicit F: Functor[F]): F[Option[B]] =
107113
mapIn(_ => b)
108114

shared/src/test/scala/mouse/FEitherSyntaxTest.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ class FEitherSyntaxTest extends MouseSuite {
4545
assertEquals(leftValue.flatMapIn(i => (i * 2).asRight[String]), leftValue)
4646
}
4747

48+
test("FEitherSyntax.flatMapOrKeepIn") {
49+
assertEquals(rightValue.flatMapOrKeepIn { case 42 => 84.asRight[String] }, List(84.asRight[String]))
50+
assertEquals(rightValue.flatMapOrKeepIn { case 84 => 42.asRight[String] }, rightValue)
51+
assertEquals(leftValue.flatMapOrKeepIn { case 42 => 84.asRight[String] }, leftValue)
52+
}
53+
4854
test("FEitherSyntax.leftWidenIn") {
4955
val initial: Option[Either[List[Int], String]] = Option(List(1).asLeft[String])
5056
val expected: Option[Either[Seq[Int], String]] = Option(Seq(1).asLeft[String])
@@ -133,6 +139,12 @@ class FEitherSyntaxTest extends MouseSuite {
133139
assertEquals(leftValue.mapIn(_ * 2), leftValue)
134140
}
135141

142+
test("FEitherSyntax.mapOrKeepIn") {
143+
assertEquals(rightValue.mapOrKeepIn { case 42 => 84 }, List(84.asRight[String]))
144+
assertEquals(rightValue.mapOrKeepIn { case 84 => 42 }, rightValue)
145+
assertEquals(leftValue.mapOrKeepIn { case 42 => 84 }, leftValue)
146+
}
147+
136148
test("FEitherSyntax.asIn") {
137149
assertEquals(rightValue.asIn(2), List(2.asRight[String]))
138150
assertEquals(leftValue.asIn(2), leftValue)

shared/src/test/scala/mouse/FOptionSyntaxTest.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ class FOptionSyntaxTest extends MouseSuite {
6767
assertEquals(List(Option.empty[Int]).flatMapIn(a => Option(a * 2)), List(Option.empty[Int]))
6868
}
6969

70+
test("FOptionSyntax.flatMapOrKeepIn") {
71+
assertEquals(List(Option(1)).flatMapOrKeepIn { case 1 => Option(2) }, List(Option(2)))
72+
assertEquals(List(Option(1)).flatMapOrKeepIn { case 2 => Option(1) }, List(Option(1)))
73+
assertEquals(List(Option.empty[Int]).flatMapOrKeepIn { case 1 => Option(2) }, List(Option.empty[Int]))
74+
}
75+
7076
test("FOptionSyntax.flatMapF") {
7177
assertEquals(List(Option(1)).flatMapF(a => List(Option(a * 2))), List(Option(2)))
7278
assertEquals(List(Option.empty[Int]).flatMapF(a => List(Option(a * 2))), List(Option.empty[Int]))
@@ -125,6 +131,12 @@ class FOptionSyntaxTest extends MouseSuite {
125131
assertEquals(List(Option.empty[Int]).mapIn(_ + 1), List(Option.empty[Int]))
126132
}
127133

134+
test("FOptionSyntax.mapOrKeepIn") {
135+
assertEquals(List(Option(1)).mapOrKeepIn { case 1 => 2 }, List(Option(2)))
136+
assertEquals(List(Option(1)).mapOrKeepIn { case 2 => 1 }, List(Option(1)))
137+
assertEquals(List(Option.empty[Int]).mapOrKeepIn { case 1 => 2 }, List(Option.empty[Int]))
138+
}
139+
128140
test("FOptionSyntax.asIn") {
129141
assertEquals(List(Option(1)).asIn(1), List(Option(1)))
130142
assertEquals(List(Option.empty[Int]).asIn(1), List(Option.empty[Int]))

0 commit comments

Comments
 (0)