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

scalaz.ExtendedInvariantAlt.scala Maven / Gradle / Ivy

// Copyright: 2017 - 2024 Sam Halliday
// License: http://www.gnu.org/licenses/lgpl-3.0.en.html

package scalaz

import scala.{ inline, Any }
import scala.annotation.switch
import scala.collection.immutable.Seq

import iotaz._
import iotaz.TList.::
import Cops.ops._

/** Implement `Deriving` (N-arity) by wrapping `InvariantAlt` (fixed arity). */
final class ExtendedInvariantAlt[F[_]] private (
  private[this] val F: InvariantAlt[F]
) extends ExtendedInvariantApplicative[F](F)
    with Deriving[F] {

  // I'm so sorry... I'm going to hell.

  override def xcoproductz[Z, A <: TList, FA <: TList](
    tcs: Prod[FA]
  )(
    f: Cop[A] => Z,
    g: Z => Cop[A]
  )(implicit
    ev: A PairedWith FA
  ): F[Z] = _xcoproductz(tcs.values.asInstanceOf[Seq[Name[F[Any]]]])(f, g)

  private def _xcoproductz[Z, A <: TList](
    tcs: Seq[Name[F[Any]]]
  )(
    f: Cop[A] => Z,
    g: Z => Cop[A]
  ): F[Z] =
    (tcs.size: @switch) match {
      case 1 =>
        val fz: Any => Z = a1 => f(Cops.from1(a1).as[A])
        val gz: Z => Any = z => g(z).value
        F.xcoproduct1(tcs(0).value)(fz, gz)
      case 2 =>
        type Two = Any :: Any :: TNil
        val fz: (Any \/ Any) => Z = e => f(Cops.from2(e).as[A])
        val gz: Z => (Any \/ Any) = z => Cops.to2(g(z).as[Two])
        F.xcoproduct2(tcs(0).value, tcs(1).value)(fz, gz)
      case 3 =>
        type Three = Any :: Any :: Any :: TNil
        val fz: (Any \/ (Any \/ Any)) => Z = e => f(Cops.from3(e).as[A])
        val gz: Z => (Any \/ (Any \/ Any)) = z => Cops.to3(g(z).as[Three])
        F.xcoproduct3(tcs(0).value, tcs(1).value, tcs(2).value)(fz, gz)

      case length =>
        type Four    = Any :: Any :: Any :: Any :: TNil
        type FourDis = Any \/ (Any \/ (Any \/ Any))
        val fe: FourDis => Cop[Four] = e => Cops.from4(e).shift(length - 4)
        val ge: Cop[Four] => FourDis = c => Cops.to4(c.shift(4 - length))
        val end: F[Cop[Four]]        = F.xcoproduct4(
          tcs(length - 4).value,
          tcs(length - 3).value,
          tcs(length - 2).value,
          tcs(length - 1).value
        )(fe, ge)

        val front: F[Cop[TList]] =
          tcs
            .take(length - 4)
            .zipWithIndex
            .foldRight(
              end.asInstanceOf[F[Cop[TList]]]
            ) { case ((tc, i), acc) =>
              val ff: (Any \/ Cop[TList]) => Cop[TList] = {
                case -\/(a) => Cop.unsafeApply[TList, Any](i, a)
                case \/-(c) => c
              }
              val fg: Cop[TList] => (Any \/ Cop[TList]) = { c =>
                if (c.index == i) -\/(c.value)
                else \/-(c)
              }
              F.xcoproduct2(tc.value, acc)(ff, fg)
            }

        val fz: Cop[TList] => Z = c => f(c.as[A])
        val gz: Z => Cop[TList] = z => g(z).as[TList]
        F.xmap(front, fz, gz)
    }

}
object ExtendedInvariantAlt {
  @inline def apply[F[_]](implicit
    F: ExtendedInvariantAlt[F]
  ): ExtendedInvariantAlt[F] = F

  /** Not implicit, to avoid breaking coherence. Always manually assign. */
  @inline def apply[F[_]](F: InvariantAlt[F]): ExtendedInvariantAlt[F] =
    new ExtendedInvariantAlt(F)

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy