All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cats.data.Binested.scala Maven / Gradle / Ivy

The newest version!
package cats
package data

import cats.arrow._

/** Compose a two-slot type constructor `F[_, _]` with two single-slot type constructors
 *  `G[_]` and `H[_]`, resulting in a two-slot type constructor with respect to the inner types.
 *  For example, `List` and `Option` both have `Functor` instances, and `Either` has a
 *  `Bifunctor` instance. Therefore, `Binested[Either, List, Option, *, *]` has a `Bifunctor`
 *  instance as well:
 *
 * {{{
 * scala> import cats.Bifunctor
 * scala> import cats.data.Binested
 * scala> import cats.implicits._
 * scala> val eitherListOption: Either[List[Int], Option[String]] = Right(Some("cats"))
 * scala> val f: Int => String = _.toString
 * scala> val g: String => String = _ + "-bifunctor"
 * scala> val binested = Binested(eitherListOption)
 * scala> val bimapped = Bifunctor[Binested[Either, List, Option, *, *]].bimap(binested)(f, g).value
 * res0: Either[List[String], Option[String]] = Right(Some("cats-bifunctor"))
 * }}}
 */
final case class Binested[F[_, _], G[_], H[_], A, B](value: F[G[A], H[B]])

object Binested extends BinestedInstances

trait BinestedInstances extends BinestedInstances0 {
  implicit def catsDataEqForBinested[F[_, _], G[_], H[_], A, B](
    implicit F: Eq[F[G[A], H[B]]]
  ): Eq[Binested[F, G, H, A, B]] =
    Eq.by(_.value)

  implicit def catsDataProfunctorForBinested[F[_, _], G[_], H[_]](implicit F: Profunctor[F],
                                                                  G: Functor[G],
                                                                  H: Functor[H]): Profunctor[Binested[F, G, H, *, *]] =
    new Profunctor[Binested[F, G, H, *, *]] {
      def dimap[A, B, C, D](fab: Binested[F, G, H, A, B])(f: C => A)(g: B => D): Binested[F, G, H, C, D] =
        Binested(F.dimap(fab.value)(G.map(_: G[C])(f))(H.map(_)(g)))
    }

  implicit def catsDataBitraverseForBinested[F[_, _], G[_], H[_]](
    implicit F0: Bitraverse[F],
    H0: Traverse[H],
    G0: Traverse[G]
  ): Bitraverse[Binested[F, G, H, *, *]] =
    new BinestedBitraverse[F, G, H] {
      implicit override def F: Bitraverse[F] = F0
      implicit override def G: Traverse[G] = G0
      implicit override def H: Traverse[H] = H0
    }
}

private[data] trait BinestedInstances0 {
  implicit def catsDataBifoldableForBinested[F[_, _], G[_], H[_]](
    implicit F0: Bifoldable[F],
    G0: Foldable[G],
    H0: Foldable[H]
  ): Bifoldable[Binested[F, G, H, *, *]] =
    new BinestedBifoldable[F, G, H] {
      implicit override def F: Bifoldable[F] = F0
      implicit override def G: Foldable[G] = G0
      implicit override def H: Foldable[H] = H0
    }

  implicit def catsDataBifunctorForBinested[F[_, _], G[_], H[_]](implicit F: Bifunctor[F],
                                                                 G: Functor[G],
                                                                 H: Functor[H]): Bifunctor[Binested[F, G, H, *, *]] =
    new Bifunctor[Binested[F, G, H, *, *]] {
      def bimap[A, B, C, D](fab: Binested[F, G, H, A, B])(f: A => C, g: B => D): Binested[F, G, H, C, D] =
        Binested(F.bimap(fab.value)(G.map(_)(f), H.map(_)(g)))
    }
}

sealed abstract class BinestedBifoldable[F[_, _], G[_], H[_]] extends Bifoldable[Binested[F, G, H, *, *]] {
  implicit def F: Bifoldable[F]
  implicit def G: Foldable[G]
  implicit def H: Foldable[H]

  def bifoldLeft[A, B, C](fab: Binested[F, G, H, A, B], c: C)(f: (C, A) => C, g: (C, B) => C): C =
    F.bifoldLeft(fab.value, c)(
      (c, ga) => G.foldLeft(ga, c)(f),
      (c, hb) => H.foldLeft(hb, c)(g)
    )

  def bifoldRight[A, B, C](fab: Binested[F, G, H, A, B], c: Eval[C])(f: (A, Eval[C]) => Eval[C],
                                                                     g: (B, Eval[C]) => Eval[C]): Eval[C] =
    F.bifoldRight(fab.value, c)(
      (ga, ec) => G.foldRight(ga, ec)(f),
      (hb, ec) => H.foldRight(hb, ec)(g)
    )
}

sealed abstract class BinestedBitraverse[F[_, _], G[_], H[_]]
    extends BinestedBifoldable[F, G, H]
    with Bitraverse[Binested[F, G, H, *, *]] {
  implicit override def F: Bitraverse[F]
  implicit override def G: Traverse[G]
  implicit override def H: Traverse[H]

  def bitraverse[I[_], A, B, C, D](
    fab: Binested[F, G, H, A, B]
  )(f: A => I[C], g: B => I[D])(implicit I: Applicative[I]): I[Binested[F, G, H, C, D]] =
    I.map(F.bitraverse(fab.value)(G.traverse(_)(f), H.traverse(_)(g)))(Binested(_))
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy