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

scalaz.Zap.scala Maven / Gradle / Ivy

The newest version!
package scalaz

import Id._

/** Functors that annihilate each other. */
trait Zap[F[_], G[_]] { self =>
  def zapWith[A, B, C](fa: F[A], gb: G[B])(f: (A, B) => C): C
  def zap[A, B](f: F[A => B], g: G[A]): B = zapWith(f, g)(_(_))
  def flip: Zap[G, F] = new Zap[G, F] {
    def zapWith[A, B, C](ga: G[A], fb: F[B])(f: (A, B) => C): C =
      self.zapWith(fb, ga)((b, a) => f(a, b))
    override def flip = self
  }
}

sealed abstract class ZapInstances {

  /** The identity functor annihilates itself. */
  implicit val identityZap: Zap[Id, Id] =
    new Zap[Id, Id] {
      def zapWith[A, B, C](a: A, b: B)(f: (A, B) => C): C = f(a, b)
    }

  /** The product of two functors annihilates their coproduct. */
  implicit def productCoproductZap[F[_], FF[_], G[_], GG[_]](implicit d1: Zap[F, FF], d2: Zap[G, GG]): Zap[λ[α => (F[α] \/ G[α])], λ[α => (FF[α], GG[α])]] =
    new Zap[λ[α => (F[α] \/ G[α])], λ[α => (FF[α], GG[α])]] {
      def zapWith[A, B, C](a: (F[A] \/ G[A]), b: (FF[B], GG[B]))(f: (A, B) => C) =
        a match {
          case -\/(fa) => d1.zapWith(fa, b._1)(f)
          case \/-(ga) => d2.zapWith(ga, b._2)(f)
        }
    }

  /** The coproduct of two functors annihilates their product. */
  implicit def coproductProductZap[F[_], FF[_], G[_], GG[_]](implicit d1: Zap[FF, F], d2: Zap[GG, G]): Zap[λ[α => (FF[α], GG[α])], λ[α => (F[α] \/ G[α])]] =
    new Zap[λ[α => (FF[α], GG[α])], λ[α => (F[α] \/ G[α])]] {
      def zapWith[A, B, C](a: (FF[A], GG[A]), b: (F[B] \/ G[B]))(f: (A, B) => C) =
        b match {
          case -\/(fb) => d1.zapWith(a._1, fb)(f)
          case \/-(gb) => d2.zapWith(a._2, gb)(f)
        }
    }

  /** A free monad and a cofree comonad annihilate each other */
  implicit def monadComonadZap[F[_], G[_]](implicit d: Zap[F, G]): Zap[Free[F, *], Cofree[G, *]] =
    new Zap[Free[F, *], Cofree[G, *]] {
      def zapWith[A, B, C](ma: Free[F, A], wb: Cofree[G, B])(f: (A, B) => C): C =
        ma.resumeC match {
          case \/-(a) => f(a, wb.head)
          case -\/(k) => d.zapWith(k.fi, wb.tail)((i, b) => zapWith(k.k(i), b)(f))
        }
    }

  /** A cofree comonad and a free monad annihilate each other */
  implicit def comonadMonadZap[F[_], G[_]](implicit d: Zap[F, G]): Zap[Cofree[F, *], Free[G, *]] =
    new Zap[Cofree[F, *], Free[G, *]] {
      def zapWith[A, B, C](wa: Cofree[F, A], mb: Free[G, B])(f: (A, B) => C): C =
        mb.resumeC match {
          case \/-(b) => f(wa.head, b)
          case -\/(k) => d.zapWith(wa.tail, k.fi)((a, i) => zapWith(a, k.k(i))(f))
        }
    }
}

object Zap extends ZapInstances




© 2015 - 2025 Weber Informatics LLC | Privacy Policy