diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index 01845da7b66..2ed3529e5a2 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -105,6 +105,25 @@ final case class OptionT[F[_], A](value: F[Option[A]]) { def foldRight[B](lb: Eval[B])(f: (A, Eval[B]) => Eval[B])(implicit F: Foldable[F]): Eval[B] = F.compose(optionInstance).foldRight(value, lb)(f) + /** + * Transform this `OptionT[F, A]` into a `[[Nested]][F, Option, A]`. + * + * An example where `toNested` can be used, is to get the `Apply.ap` function with the + * behavior from the composed `Apply` instances from `F` and `Option`, which is + * inconsistent with the behavior of the `ap` from `Monad` of `OptionT`. + * + * {{{ + * scala> import cats.implicits._ + * scala> import cats.data.OptionT + * scala> val ff: OptionT[List, Int => String] = + * | OptionT(List(Option(_.toString), None)) + * scala> val fa: OptionT[List, Int] = OptionT(List(Option(1), Option(2))) + * scala> ff.ap(fa) + * res0: OptionT[List,String] = OptionT(List(Some(1), Some(2), None)) + * scala> OptionT(ff.toNested.ap(fa.toNested).value) + * res1: OptionT[List,String] = OptionT(List(Some(1), Some(2), None, None)) + * }}} + */ def toNested: Nested[F, Option, A] = Nested(value) } @@ -122,8 +141,8 @@ object OptionT extends OptionTInstances { /** * Transforms an `Option` into an `OptionT`, lifted into the specified `Applicative`. * - * Note: The return type is a FromOptionPartiallyApplied[F], which has an apply method - * on it, allowing you to call fromOption like this: + * Note: The return type is a `FromOptionPartiallyApplied[F]`, which has an apply method + * on it, allowing you to call `fromOption` like this: * {{{ * scala> import cats.implicits._ * scala> val o: Option[Int] = Some(2) @@ -142,7 +161,6 @@ object OptionT extends OptionTInstances { /** * Lifts the `F[A]` Functor into an `OptionT[F, A]`. - * */ def liftF[F[_], A](fa: F[A])(implicit F: Functor[F]): OptionT[F, A] = OptionT(F.map(fa)(Some(_))) } diff --git a/core/src/main/scala/cats/data/XorT.scala b/core/src/main/scala/cats/data/XorT.scala index 2a6e11d9bfc..894d0831c64 100644 --- a/core/src/main/scala/cats/data/XorT.scala +++ b/core/src/main/scala/cats/data/XorT.scala @@ -175,6 +175,32 @@ final case class XorT[F[_], A, B](value: F[A Xor B]) { def show(implicit show: Show[F[A Xor B]]): String = show.show(value) + /** + * Transform this `XorT[F, A, B]` into a `[[Nested]][F, A Xor ?, B]`. + * + * An example where `toNested` can be used, is to get the `Apply.ap` function with the + * behavior from the composed `Apply` instances from `F` and `Xor[A, ?]`, which is + * inconsistent with the behavior of the `ap` from `Monad` of `XorT`. + * + * {{{ + * scala> import cats.data.{Nested, Xor, XorT} + * scala> import cats.implicits._ + * scala> val ff: XorT[List, String, Int => String] = + * | XorT(List(Xor.right(_.toString), Xor.left("error"))) + * scala> val fa: XorT[List, String, Int] = + * | XorT(List(Xor.right(1), Xor.right(2))) + * scala> type ErrorOr[A] = String Xor A + * scala> type ListErrorOr[A] = Nested[List, ErrorOr, A] + * scala> ff.ap(fa) + * res0: XorT[List,String,String] = XorT(List(Right(1), Right(2), Left(error))) + * scala> XorT((ff.toNested: ListErrorOr[Int => String]).ap(fa.toNested: ListErrorOr[Int]).value) + * res1: XorT[List,String,String] = XorT(List(Right(1), Right(2), Left(error), Left(error))) + * }}} + * + * Note that we need the `ErrorOr` type alias above because otherwise we can't use the + * syntax function `ap` on `Nested[List, A Xor ?, B]`. This won't be needed after cats has + * decided [[https://github.com/typelevel/cats/issues/1073 how to handle the SI-2717 fix]]. + */ def toNested: Nested[F, A Xor ?, B] = Nested[F, A Xor ?, B](value) }