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

scalaz.Endomorphic.scala Maven / Gradle / Ivy

The newest version!
package scalaz

/** Endomorphisms have special properties among arrows, so are captured in this newtype.
  *
  * Endomorphic[Function1, A] is equivalent to Endo[A]
  */
final case class Endomorphic[=>:[_, _], A](run: A =>: A) {

  final def compose(that: Endomorphic[=>:, A])(implicit F: Compose[=>:]): Endomorphic[=>:, A] =
    Endomorphic[=>:, A](F.compose(run, that.run))

  final def andThen(that: Endomorphic[=>:, A])(implicit F: Compose[=>:]): Endomorphic[=>:, A] =
    that.compose(this)

}

object Endomorphic extends EndomorphicInstances {

  /** Endomorphic Kleisli arrow */
  final def endoKleisli[F[_]: Monad, A](f: A => F[A]): Endomorphic[Kleisli[F, *, *], A] =
    Endomorphic[Kleisli[F, *, *], A](Kleisli(f))
}

sealed abstract class EndomorphicInstances extends EndomorphicInstances0 {
  implicit def kleisliEndoInstance[F[_]: Monad, A]: Monoid[Endomorphic[Kleisli[F, *, *], A]] =
    Endomorphic.endomorphicMonoid[Kleisli[F, *, *], A]

  implicit def cokleisliEndoInstance[F[_]: Comonad, A]: Monoid[Endomorphic[Cokleisli[F, *, *], A]] =
    Endomorphic.endomorphicMonoid[Cokleisli[F, *, *], A]
}

sealed abstract class EndomorphicInstances0 extends EndomorphicInstances1 {
  implicit def endomorphicMonoid[=>:[_, _], A](implicit G: Category[=>:]): Monoid[Endomorphic[=>:, A]] =
    new Monoid[Endomorphic[=>:, A]] with EndomorphicSemigroup[=>:, A] {
      val F: Compose[=>:] = G
      def zero: Endomorphic[=>:, A] = Endomorphic(G.id)
    }
}

sealed abstract class EndomorphicInstances1 extends EndomorphicInstances2 {
  implicit def kleisliEndoSemigroup[F[_]: Bind, A]: Semigroup[Endomorphic[Kleisli[F, *, *], A]] =
    Endomorphic.endomorphicSemigroup[Kleisli[F, *, *], A]

  implicit def cokleisliEndoSemigroup[F[_]: Cobind, A]: Semigroup[Endomorphic[Cokleisli[F, *, *], A]] =
    Endomorphic.endomorphicSemigroup[Cokleisli[F, *, *], A]
}

sealed abstract class EndomorphicInstances2 {
  implicit def endomorphicSemigroup[=>:[_, _], A](implicit G: Compose[=>:]): Semigroup[Endomorphic[=>:, A]] =
    new EndomorphicSemigroup[=>:, A] {
      val F = G
    }
}

private trait EndomorphicSemigroup[=>:[_, _], A] extends Semigroup[Endomorphic[=>:, A]] {
  implicit def F: Compose[=>:]
  def append(f1: Endomorphic[=>:, A], f2: => Endomorphic[=>:, A]) = Endomorphic(F.compose(f1.run, f2.run))
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy