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

cats.sequence.sequence.scala Maven / Gradle / Ivy

/*
 * Originally adapted from shapeless-contrib scalaz
 * https://github.com/typelevel/shapeless-contrib/blob/v0.4/scalaz/main/scala/sequence.scala
 *
 */
package cats.sequence

import shapeless._

import cats._
import shapeless.ops.hlist.ZipWithKeys
import shapeless.ops.record.{Values, Keys}

import scala.annotation.implicitNotFound

trait HListApply2[FH, OutT] {
  type Out

  def apply(fh: FH, outT: OutT): Out
}

object HListApply2 {
  type Aux[FH, OutT, Out0] = HListApply2[FH, OutT] { type Out = Out0 }

  implicit def mkHListApply2[F[_], H, T <: HList]
    (implicit app: Apply[F]): Aux[F[H], F[T], F[H :: T]] =
      new HListApply2[F[H], F[T]] {
        type Out = F[H :: T]

        def apply(fh: F[H], outT: F[T]): Out = app.map2(fh, outT)(_ :: _)
      }

  implicit def mkHListApply2a[F[_, _], A, H, T <: HList]
    (implicit app: Apply[F[A, ?]]): Aux[F[A, H], F[A, T], F[A, H :: T]] = mkHListApply2[F[A, ?], H, T]

  implicit def mkHListApply3right[G[_], F[_[_], _, _], A, H, T <: HList]
    (implicit app: Apply[F[G, A, ?]]): Aux[F[G, A, H], F[G, A, T], F[G, A, H :: T]] = mkHListApply2[F[G, A, ?], H, T]
}

@implicitNotFound("cannot construct sequencer, make sure that every item of you hlist ${L} is an Applicative")
trait Sequencer[L <: HList] {
  type Out

  def apply(in: L): Out
}

trait LowPrioritySequencer {
  type Aux[L <: HList, Out0] = Sequencer[L] { type Out = Out0 }

  implicit def consSequencerAux[FH, FT <: HList, OutT]
    (implicit st: Aux[FT, OutT], ap: HListApply2[FH, OutT]): Aux[FH :: FT, ap.Out] =
      new Sequencer[FH :: FT] {
        type Out = ap.Out

        def apply(in: FH :: FT): Out = ap(in.head, st(in.tail))
      }
}

object Sequencer extends LowPrioritySequencer {
  implicit def nilSequencerAux[F[_] : Applicative]: Aux[HNil, F[HNil]] =
    new Sequencer[HNil] {
      type Out = F[HNil]

      def apply(in: HNil): F[HNil] = Applicative[F].pure(HNil: HNil)
    }

  implicit def singleSequencerAux[FH]
    (implicit un: Unapply[Functor, FH]): Aux[FH :: HNil, un.M[un.A :: HNil]] =
      new Sequencer[FH :: HNil] {
        type Out = un.M[un.A :: HNil]

        def apply(in: FH :: HNil): Out = un.TC.map(un.subst(in.head)) {
          _ :: HNil
        }
      }
}


trait ValueSequencer[L <: HList] {
  type Out

  def apply(in: L): Out
}


object ValueSequencer {
  type Aux[L <: HList, Out0] = ValueSequencer[L] { type Out = Out0 }

  implicit def recordValueAux[L <: HList, V <: HList]
    (implicit values: Values.Aux[L, V], sequencer: Sequencer[V]): Aux[L, sequencer.Out] =
      new ValueSequencer[L] {
        type Out = sequencer.Out

        def apply(in: L): Out = sequencer(values(in))
      }

}


@implicitNotFound("cannot construct sequencer, make sure that every field value of you record ${L} is an Applicative")
trait RecordSequencer[L <: HList] {
  type Out

  def apply(in: L): Out
}


object RecordSequencer {
  type Aux[L <: HList, Out0] = RecordSequencer[L] { type Out = Out0 }

  implicit def mkRecordSequencer[L <: HList, VFOut, F[_], K <: HList, VOut <: HList]
    ( implicit
      vs: ValueSequencer.Aux[L, VFOut],
      un: Unapply.Aux1[Functor, VFOut, F, VOut],
      keys: Keys.Aux[L, K],
      zip: ZipWithKeys[K, VOut]
    ): Aux[L, F[zip.Out]] =
      new RecordSequencer[L] {
        type Out = F[zip.Out]

        def apply(in: L): Out = {
          un.TC.map(un.subst(vs(in)))(zip(_))
        }
  }

  implicit def mkRecordSequencer2Right[L <: HList, VFOut, A, F[_, _], K <: HList, VOut <: HList]
    ( implicit
      vs: ValueSequencer.Aux[L, VFOut],
      un: Unapply.Aux2Right[Functor, VFOut, F, A, VOut],
      keys: Keys.Aux[L, K],
      zip: ZipWithKeys[K, VOut]
    ): Aux[L, F[A, zip.Out]] =
      mkRecordSequencer[L, VFOut, F[A, ?], K, VOut]

  implicit def mkRecordSequencer3Right[L <: HList, VFOut, A, G[_], F[_[_], _, _], K <: HList, VOut <: HList]
    ( implicit
      vs: ValueSequencer.Aux[L, VFOut],
      un: Unapply.Aux3MTRight[Functor, VFOut, F, G, A, VOut],
      keys: Keys.Aux[L, K],
      zip: ZipWithKeys[K, VOut]
    ): Aux[L, F[G, A, zip.Out]] =
      mkRecordSequencer[L, VFOut, F[G, A, ?], K, VOut]
}

trait GenericSequencer[L <: HList, T] {
  type Out

  def apply(l: L): Out
}

object GenericSequencer {
  type Aux[L <: HList, T, Out0] = GenericSequencer[L, T] { type Out = Out0 }

  implicit def mkGenericSequencer[L <: HList, T, SOut <: HList, FOut, F[_]]
    ( implicit
      rs: RecordSequencer.Aux[L, FOut],
      gen: LabelledGeneric.Aux[T, SOut],
      un: Unapply.Aux1[Functor, FOut, F, SOut]
    ): Aux[L, T, F[T]] =
      new GenericSequencer[L, T] {
        type Out = F[T]

        def apply(in: L): Out = {
          un.TC.map(un.subst(rs(in)))(gen.from)
      }
  }

  implicit def mkGenericSequencer2Right[L <: HList, T, SOut <: HList, FOut, A, F[_, _]]
    ( implicit
      rs: RecordSequencer.Aux[L, FOut],
      gen: LabelledGeneric.Aux[T, SOut],
      un: Unapply.Aux2Right[Functor, FOut, F, A, SOut]
    ): Aux[L, T, F[A, T]] =
      mkGenericSequencer[L, T, SOut, FOut, F[A, ?]]

  implicit def mkGenericSequencer3Right[L <: HList, T, SOut <: HList, FOut, A, G[_], F[_[_], _, _]]
    ( implicit
      rs: RecordSequencer.Aux[L, FOut],
      gen: LabelledGeneric.Aux[T, SOut],
      un: Unapply.Aux3MTRight[Functor, FOut, F, G, A, SOut]
    ): Aux[L, T, F[G, A, T]] =
      mkGenericSequencer[L, T, SOut, FOut, F[G, A, ?]]
}


trait LowPrioritySequenceOps {
  import SequenceOps._
  // fallback for non-records
  implicit def mkNonRecordOps[L <: HList](l: L): NonRecordOps[L] = new NonRecordOps(l)
}


trait SequenceOps extends LowPrioritySequenceOps {
  import SequenceOps._
  implicit def mkRecordOps[L <: HList](l: L)
                                      (implicit keys: Keys[L]): RecordOps[L] = new RecordOps(l)

  object sequence extends ProductArgs {
    def applyProduct[L <: HList](l: L)(implicit seq: Sequencer[L]): seq.Out = seq(l)
  }

  object sequenceRecord extends RecordArgs {
    def applyRecord[L <: HList](l: L)(implicit seq: RecordSequencer[L]): seq.Out = seq(l)
  }

  class sequenceGen[T] extends RecordArgs {
    def applyRecord[L <: HList](l: L)(implicit seq: GenericSequencer[L, T]): seq.Out = seq(l)
  }

  def sequenceGeneric[T] = new sequenceGen[T]

}

object SequenceOps {
  // Syntax for non-records
  class NonRecordOps[L <: HList](self: L) {
    def sequence(implicit seq: Sequencer[L]): seq.Out = seq(self)
  }

  // Syntax for records
  class RecordOps[L <: HList](self: L) {
    def sequence(implicit seq: RecordSequencer[L]): seq.Out = seq(self)
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy