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

scalaz.NullArgument.scala Maven / Gradle / Ivy

package scalaz

final class NullArgument[A, B] private(_apply: Option[A] => B) {
  def apply(a: Option[A]): B = _apply(a)

  def dimap[C, D](f: C => A, g: B => D): NullArgument[C, D] =
    NullArgument(c => g(_apply(c.map(f))))

  def map[C](f: B => C): NullArgument[A, C] =
    NullArgument(_apply andThen f)

  def contramap[C](f: C => A): NullArgument[C, B] =
    NullArgument(c => apply(c.map(f)))

  def flatMap[C](f: B => NullArgument[A, C]): NullArgument[A, C] =
    NullArgument(a => f(apply(a))(a))

  def ap[C](f: NullArgument[A, B => C]): NullArgument[A, C] =
    for {
      ff <- f
      bb <- this
    } yield ff(bb)

  def zip[C](x: NullArgument[A, C]): NullArgument[A, (B, C)] =
    for {
      b <- this
      c <- x
    } yield (b, c)

  def ***[C, D](x: NullArgument[C, D]): NullArgument[(A, C), (B, D)] =
    NullArgument {
      case None => (apply(None), x(None))
      case Some((a, c)) => (apply(Some(a)), x(Some(c)))
    }

  def +++[C, D](x: NullArgument[C, D]): NullArgument[A \/ C, B \/ D] =
    left[D] compose x.right[A]

  def left[C]: NullArgument[A \/ C, B \/ C] =
    NullArgument {
      case None => -\/(apply(None))
      case Some(-\/(a)) => -\/(apply(Some(a)))
      case Some(c @ \/-(_)) => c.coerceLeft
    }

  def right[C]: NullArgument[C \/ A, C \/ B] =
    NullArgument {
      case None => \/-(apply(None))
      case Some(\/-(a)) => \/-(apply(Some(a)))
      case Some(c @ -\/(_)) => c.coerceRight
    }

  def compose[C](f: NullArgument[C, A]): NullArgument[C, B] =
    NullArgument {
      case None => apply(None)
      case c @ Some(_) => apply(Some(f(c)))
    }

  def andThen[C](g: NullArgument[B, C]): NullArgument[A, C] =
    g compose this

  def |+|(x: NullArgument[A, B])(implicit S: Semigroup[B]): NullArgument[A, B] =
    for {
      b1 <- this
      b2 <- x
    } yield S.append(b1, b2)

  def cokleisli: Cokleisli[Option, A, B] =
    Cokleisli(_apply)

  def on[F[_]](o: OptionT[F, A])(implicit F: Functor[F]): F[B] =
    F.map(o.run)(_apply)

  def lower: A => B =
    a => apply(Some(a))

  def never: B =
    apply(None)

  def zero(implicit M: Monoid[A]): B =
    lower(M.zero)

  def pair: (A => B, B) =
    (a => apply(Some(a)), apply(None))

}

object NullArgument extends NullArgumentInstances {
  def apply[A, B](f: Option[A] => B): NullArgument[A, B] =
    new (NullArgument[A, B])(f)

  def always[A, B](b: => B): NullArgument[A, B] =
    NullArgument(_ => b)

  def zero[A, B](implicit M: Monoid[B]): NullArgument[A, B] =
    always(M.zero)

  def pair[A, B](f: A => B, b: => B): NullArgument[A, B] =
    NullArgument((_: Option[A]) match {
      case None => b
      case Some(a) => f(a)
    })

  def cokleisli[A, B](c: Cokleisli[Option, A, B]): NullArgument[A, B] =
    NullArgument(c.run)
}

sealed abstract class NullArgumentInstances0 {

  implicit def nullArgumentSemigroup[A, B](implicit M0: Semigroup[B]): Semigroup[NullArgument[A, B]] =
    new NullArgumentSemigroup[A, B] {
      override val M = M0
    }

  implicit val nullArgumentProfunctor: Profunctor[NullArgument] =
    new Profunctor[NullArgument] {
      def mapfst[A, B, C](fab: NullArgument[A, B])(f: C => A) =
        fab contramap f
      def mapsnd[A, B, C](fab: NullArgument[A, B])(f: B => C) =
        fab map f
      override def dimap[A, B, C, D](fab: NullArgument[A, B])(f: C => A)(g: B => D) =
        fab.dimap(f, g)
    }

}

sealed abstract class NullArgumentInstances extends NullArgumentInstances0 {

  implicit def nullArgumentMonoid[A, B](implicit M0: Monoid[B]): Monoid[NullArgument[A, B]] =
    new NullArgumentMonoid[A, B] {
      override val M = M0
    }

  implicit val nullArgumentCategory: Split[NullArgument] & Profunctor[NullArgument] =
    new Split[NullArgument] with Profunctor[NullArgument] {
      override def compose[A, B, C](f: NullArgument[B, C], g: NullArgument[A, B]): NullArgument[A, C] =
        f compose g
      override def split[A, B, C, D](f: NullArgument[A, B], g: NullArgument[C, D]) =
        f *** g
      override def mapfst[A, B, C](r: NullArgument[A, B])(f: C => A) =
        r contramap f
      override def mapsnd[A, B, C](r: NullArgument[A, B])(f: B => C) =
        r map f
    }

  implicit def nullArgumentMonad[X]: Monad[NullArgument[X, *]] & BindRec[NullArgument[X, *]] =
    new Monad[NullArgument[X, *]] with BindRec[NullArgument[X, *]] {
      override def ap[A, B](a: => NullArgument[X, A])(f: => NullArgument[X, A => B]) =
        a ap f
      override def map[A, B](a: NullArgument[X, A])(f: A => B) =
        a map f
      override def point[A](a: => A): NullArgument[X, A] =
        NullArgument.always(a)
      override def bind[A, B](a: NullArgument[X, A])(f: A => NullArgument[X, B]) =
        a flatMap f
      override def tailrecM[A, B](a: A)(f: A => NullArgument[X, A \/ B]) =
        NullArgument{ t =>
          @annotation.tailrec
          def go(a0: A): B =
            f(a0)(t) match {
              case \/-(b) => b
              case -\/(a1) => go(a1)
            }
          go(a)
        }
    }

  implicit def nullArgumentContravariant[X]: Contravariant[NullArgument[*, X]] =
    new Contravariant[NullArgument[*, X]] {
      override def contramap[A, B](a: NullArgument[A, X])(f: B => A) =
        a contramap f
    }
}

private trait NullArgumentSemigroup[A, B] extends Semigroup[NullArgument[A, B]] {
  implicit val M: Semigroup[B]

  override def append(a1: NullArgument[A, B], a2: => NullArgument[A, B]) =
    a1 |+| a2
}

private trait NullArgumentMonoid[A, B] extends Monoid[NullArgument[A, B]] with NullArgumentSemigroup[A, B] {
  implicit val M: Monoid[B]

  override def zero =
    NullArgument.zero
}

// vim: expandtab:ts=2:sw=2




© 2015 - 2025 Weber Informatics LLC | Privacy Policy