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

zio.prelude.experimental.DistributiveProd.scala Maven / Gradle / Ivy

The newest version!
package zio.prelude
package experimental

import zio.prelude.newtypes.{Prod, Sum}

trait DistributiveProd[A] {
  def Sum: Associative[Sum[A]]
  def Prod: Associative[Prod[A]]
  def sum(l: => A, r: => A): A  = Sum.combine(newtypes.Sum(l), newtypes.Sum(r))
  def prod(l: => A, r: => A): A = Prod.combine(newtypes.Prod(l), newtypes.Prod(r))
}

object DistributiveProd extends DistributiveProdLowPriorityImplicits {

  /**
   * Summons an implicit `DistributiveProd[A]`.
   */
  def apply[A](implicit distributiveProd: DistributiveProd[A]): DistributiveProd[A] = distributiveProd

  implicit lazy val BigDecimalAnnihilationPartialDivideSubtract
    : Annihilation[BigDecimal] with PartialDivide[BigDecimal] with Subtract[BigDecimal] =
    new Annihilation[BigDecimal] with PartialDivide[BigDecimal] with Subtract[BigDecimal] {
      override def sum(l: => BigDecimal, r: => BigDecimal): BigDecimal                  = l + r
      override def divideOption(l: => BigDecimal, r: => BigDecimal): Option[BigDecimal] =
        if (r != BigDecimal(0)) Some(l / r) else None
      override def prod(l: => BigDecimal, r: => BigDecimal): BigDecimal                 = l * r
      override def subtract(l: => BigDecimal, r: => BigDecimal): BigDecimal             = l - r
      override def annihilation: BigDecimal                                             = 0.0
      val Sum: Commutative[Sum[BigDecimal]] with Inverse[Sum[BigDecimal]]               = Associative.BigDecimalSumCommutativeInverse
      val Prod: Commutative[Prod[BigDecimal]] with PartialInverse[Prod[BigDecimal]]     =
        Associative.BigDecimalProdCommutativePartialInverse
    }

  implicit lazy val ByteAnnihilationSubtract: Annihilation[Byte] with Subtract[Byte] =
    new Annihilation[Byte] with Subtract[Byte] {
      override def sum(l: => Byte, r: => Byte): Byte                    = (l + r).toByte
      override def prod(l: => Byte, r: => Byte): Byte                   = (l * r).toByte
      override def subtract(l: => Byte, r: => Byte): Byte               = (l - r).toByte
      override def annihilation: Byte                                   = 0
      val Sum: Commutative[Sum[Byte]] with Inverse[Sum[Byte]]           = Associative.ByteSumCommutativeInverse
      val Prod: Commutative[Prod[Byte]] with PartialInverse[Prod[Byte]] = Associative.ByteProdCommutativePartialInverse
    }

  implicit lazy val CharAnnihilationSubtract: Annihilation[Char] with Subtract[Char] =
    new Annihilation[Char] with Subtract[Char] {
      override def sum(l: => Char, r: => Char): Char                    = (l + r).toChar
      override def prod(l: => Char, r: => Char): Char                   = (l * r).toChar
      override def subtract(l: => Char, r: => Char): Char               = (l - r).toChar
      override def annihilation: Char                                   = 0
      val Sum: Commutative[Sum[Char]] with Inverse[Sum[Char]]           = Associative.CharSumCommutativeInverse
      val Prod: Commutative[Prod[Char]] with PartialInverse[Prod[Char]] = Associative.CharProdCommutativePartialInverse
    }

  implicit lazy val DoubleAnnihilationPartialDivideSubtract
    : Annihilation[Double] with PartialDivide[Double] with Subtract[Double] =
    new Annihilation[Double] with PartialDivide[Double] with Subtract[Double] {
      override def sum(l: => Double, r: => Double): Double                  = l + r
      override def divideOption(l: => Double, r: => Double): Option[Double] = if (r != 0) Some(l / r) else None
      override def prod(l: => Double, r: => Double): Double                 = l * r
      override def subtract(l: => Double, r: => Double): Double             = l - r
      override def annihilation: Double                                     = 0.0
      val Sum: Commutative[Sum[Double]] with Inverse[Sum[Double]]           = Associative.DoubleSumCommutativeInverse
      val Prod: Commutative[Prod[Double]] with PartialInverse[Prod[Double]] =
        Associative.DoubleProdCommutativePartialInverse
    }

  implicit lazy val FloatAnnihilationPartialDivideSubtract
    : Annihilation[Float] with PartialDivide[Float] with Subtract[Float] =
    new Annihilation[Float] with PartialDivide[Float] with Subtract[Float] {
      override def sum(l: => Float, r: => Float): Float                   = l + r
      override def divideOption(l: => Float, r: => Float): Option[Float]  = if (r != 0) Some(l / r) else None
      override def prod(l: => Float, r: => Float): Float                  = l * r
      override def subtract(l: => Float, r: => Float): Float              = l - r
      override def annihilation: Float                                    = 0.0f
      val Sum: Commutative[Sum[Float]] with Inverse[Sum[Float]]           = Associative.FloatSumCommutativeInverse
      val Prod: Commutative[Prod[Float]] with PartialInverse[Prod[Float]] =
        Associative.FloatProdCommutativePartialInverse
    }

  implicit lazy val IntAnnihilationSubtract: Annihilation[Int] with Subtract[Int] =
    new Annihilation[Int] with Subtract[Int] {
      override def sum(l: => Int, r: => Int): Int                     = l + r
      override def prod(l: => Int, r: => Int): Int                    = l * r
      override def subtract(l: => Int, r: => Int): Int                = l - r
      override def annihilation: Int                                  = 0
      val Sum: Commutative[Sum[Int]] with Inverse[Sum[Int]]           = Associative.IntSumCommutativeInverse
      val Prod: Commutative[Prod[Int]] with PartialInverse[Prod[Int]] = Associative.IntProdCommutativePartialInverse
    }

  implicit lazy val LongAnnihilationSubtract: Annihilation[Long] with Subtract[Long] =
    new Annihilation[Long] with Subtract[Long] {
      override def sum(l: => Long, r: => Long): Long                    = l + r
      override def prod(l: => Long, r: => Long): Long                   = l * r
      override def subtract(l: => Long, r: => Long): Long               = l - r
      override def annihilation: Long                                   = 0
      val Sum: Commutative[Sum[Long]] with Inverse[Sum[Long]]           = Associative.LongSumCommutativeInverse
      val Prod: Commutative[Prod[Long]] with PartialInverse[Prod[Long]] = Associative.LongProdCommutativePartialInverse
    }

  implicit def ParSeqDistributiveProd[A]: DistributiveProd[ParSeq[Unit, A]] =
    new DistributiveProd[ParSeq[Unit, A]] {
      val Sum: Associative[Sum[ParSeq[Unit, A]]]   = Associative.ParSeqSumCommutativeIdentity
      val Prod: Associative[Prod[ParSeq[Unit, A]]] = Associative.ParSeqProdIdentity
    }

  implicit lazy val ShortAnnihilationSubtract: Annihilation[Short] with Subtract[Short] =
    new Annihilation[Short] with Subtract[Short] {
      override def sum(l: => Short, r: => Short): Short                   = (l + r).toShort
      override def prod(l: => Short, r: => Short): Short                  = (l * r).toShort
      override def subtract(l: => Short, r: => Short): Short              = (l - r).toShort
      override def annihilation: Short                                    = 0
      val Sum: Commutative[Sum[Short]] with Inverse[Sum[Short]]           = Associative.ShortSumCommutativeInverse
      val Prod: Commutative[Prod[Short]] with PartialInverse[Prod[Short]] =
        Associative.ShortProdCommutativePartialInverse
    }

  implicit def ZioCauseDistributiveProd[A]: DistributiveProd[zio.Cause[A]] =
    new DistributiveProd[zio.Cause[A]] {
      val Sum: Associative[Sum[zio.Cause[A]]]   = Associative.zioCauseSumCommutativeIdentity
      val Prod: Associative[Prod[zio.Cause[A]]] = Associative.zioCauseProdIdentity
    }

}

trait DistributiveProdLowPriorityImplicits {

  implicit def FxCauseDistributiveProd[A]: DistributiveProd[fx.Cause[A]] =
    new DistributiveProd[fx.Cause[A]] {
      val Sum: Associative[Sum[fx.Cause[A]]]   = Associative.FxCauseSumCommutative
      val Prod: Associative[Prod[fx.Cause[A]]] = Associative.FxCauseProdAssociative
    }

}

trait DistributiveProdSyntax {

  /**
   * Provides infix syntax for adding or multiplying two values.
   */
  implicit class DistributiveProdOps[A](private val l: A) {

    /**
     * A symbolic alias for `sum`.
     */
    def +++(r: => A)(implicit distributiveProd: DistributiveProd[A]): A =
      distributiveProd.sum(l, r)

    /**
     * Add two values.
     */
    def sum(r: => A)(implicit distributiveProd: DistributiveProd[A]): A =
      distributiveProd.sum(l, r)

    /**
     * A symbolic alias for `prod`.
     */
    def ***(r: => A)(implicit distributiveProd: DistributiveProd[A]): A =
      distributiveProd.prod(l, r)

    /**
     * Multiply two values.
     */
    def prod(r: => A)(implicit distributiveProd: DistributiveProd[A]): A =
      distributiveProd.prod(l, r)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy