Skip to content

Commit 74acdef

Browse files
committed
Merge pull request #571 from liff/topic/subflatMap
Add transform and subflatMap to OptionT and XorT
2 parents 502c5fa + d4393aa commit 74acdef

4 files changed

Lines changed: 36 additions & 0 deletions

File tree

core/src/main/scala/cats/data/OptionT.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ final case class OptionT[F[_], A](value: F[Option[A]]) {
3939
case None => F.pure(None)
4040
})
4141

42+
def transform[B](f: Option[A] => Option[B])(implicit F: Functor[F]): OptionT[F, B] =
43+
OptionT(F.map(value)(f))
44+
45+
def subflatMap[B](f: A => Option[B])(implicit F: Functor[F]): OptionT[F, B] =
46+
transform(_.flatMap(f))
47+
4248
def getOrElse(default: => A)(implicit F: Functor[F]): F[A] =
4349
F.map(value)(_.getOrElse(default))
4450

core/src/main/scala/cats/data/XorT.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ case class XorT[F[_], A, B](value: F[A Xor B]) {
6161
def flatMapF[AA >: A, D](f: B => F[AA Xor D])(implicit F: Monad[F]): XorT[F, AA, D] =
6262
flatMap(f andThen XorT.apply)
6363

64+
def transform[C, D](f: Xor[A, B] => Xor[C, D])(implicit F: Functor[F]): XorT[F, C, D] =
65+
XorT(F.map(value)(f))
66+
67+
def subflatMap[AA >: A, D](f: B => AA Xor D)(implicit F: Functor[F]): XorT[F, AA, D] =
68+
transform(_.flatMap(f))
69+
6470
def map[D](f: B => D)(implicit F: Functor[F]): XorT[F, A, D] = bimap(identity, f)
6571

6672
def leftMap[C](f: A => C)(implicit F: Functor[F]): XorT[F, C, B] = bimap(f, identity)

tests/src/test/scala/cats/tests/OptionTTests.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,18 @@ class OptionTTests extends CatsSuite {
116116
OptionT[Xor[String, ?], Int](xor).show should === ("Xor.Right(Some(1))")
117117
}
118118

119+
test("transform consistent with value.map") {
120+
forAll { (o: OptionT[List, Int], f: Option[Int] => Option[String]) =>
121+
o.transform(f) should === (OptionT(o.value.map(f)))
122+
}
123+
}
124+
125+
test("subflatMap consistent with value.map+flatMap") {
126+
forAll { (o: OptionT[List, Int], f: Int => Option[String]) =>
127+
o.subflatMap(f) should === (OptionT(o.value.map(_.flatMap(f))))
128+
}
129+
}
130+
119131
checkAll("OptionT[List, Int]", MonadCombineTests[OptionT[List, ?]].monad[Int, Int, Int])
120132
checkAll("MonadOptionT[List, ?]]", SerializableTests.serializable(Monad[OptionT[List, ?]]))
121133

tests/src/test/scala/cats/tests/XorTTests.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,16 @@ class XorTTests extends CatsSuite {
9191
val xort = XorT.right[Id, String, Int](10)
9292
xort.recoverWith { case "xort" => XorT.right[Id, String, Int](5) } should === (xort)
9393
}
94+
95+
test("transform consistent with value.map") {
96+
forAll { (xort: XorT[List, String, Int], f: String Xor Int => Long Xor Double) =>
97+
xort.transform(f) should === (XorT(xort.value.map(f)))
98+
}
99+
}
100+
101+
test("subflatMap consistent with value.map+flatMap") {
102+
forAll { (xort: XorT[List, String, Int], f: Int => String Xor Double) =>
103+
xort.subflatMap(f) should === (XorT(xort.value.map(_.flatMap(f))))
104+
}
105+
}
94106
}

0 commit comments

Comments
 (0)