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

perspective.derivation.productK.scala Maven / Gradle / Ivy

The newest version!
package perspective.derivation

import cats.Applicative
import perspective._

import scala.annotation.tailrec
import scala.deriving._
import scala.compiletime._

opaque type ProductK[F[_], T <: Tuple] = Tuple.Map[T, F]
type ProductKPar[T <: Tuple] = [F[_]] =>> ProductK[F, T]
object ProductK extends ProductKGather:
  def of[F[_], T <: Tuple](t: Tuple.Map[T, F]): ProductK[F, T] = t
  
  extension [F[_], T <: Tuple](p: ProductK[F, T]) def tuple: Tuple.Map[T, F] = p
  
  /* TODO: Determine if provide premade implicits for small (n < 22) tuple sizes has a positive effect on classfile size
  given [F[_], T1](using t1: F[T1]): ProductK[F, Tuple1[T1]] = Tuple1(t1)
  given [F[_], T1, T2](using t1: F[T1], t2: F[T2]): ProductK[F, (T1, T2)] = (t1, t2)
  given [F[_], T1, T2, T3](using t1: F[T1], t2: F[T2], t3: F[T3]): ProductK[F, (T1, T2, T3)] = (t1, t2, t3)
  given [F[_], T1, T2, T3, T4](using t1: F[T1], t2: F[T2], t3: F[T3], t4: F[T4]): ProductK[F, (T1, T2, T3, T4)] = (t1, t2, t3, t4)
   */
  
  given productKInstance[T <: Tuple](
    using size: ValueOf[Tuple.Size[T]]
  ): RepresentableKC[ProductKPar[T]] with TraverseKC[ProductKPar[T]] with
    type RepresentationK[_] = Finite[Tuple.Size[T]]
    
    extension[A[_], B, C](fa: ProductK[A, T]) override def foldLeftK(b: B)(f: B => A ~>#: B): B = 
      fa.productIterator.foldLeft(b) { (acc, v) =>
        val withAcc = f(acc)
        withAcc(v.asInstanceOf[A[Any]])
      }

    extension[G[_]: Applicative, A[_], B[_], C](fa: ProductK[A, T]) def traverseK(f: A ~>: Compose2[G, B]): G[ProductK[B, T]] =
      val it = fa.productIterator.asInstanceOf[Iterator[A[Any]]]
    
      @tailrec
      def inner(acc: G[List[B[Any]]]): G[ProductK[B, T]] =
        if (it.hasNext) {
          val obj = it.next()
          inner(Applicative[G].map2(f(obj), acc)((v, a) => v :: a))
        } else
          Applicative[G].map(acc)(a => Tuple.fromArray(a.reverseIterator.toArray).asInstanceOf[ProductK[B, T]])

      inner(Applicative[G].pure(List.empty[B[Any]]))

    def tabulateK[A[_], C](f: RepresentationK ~>: A): ProductK[A, T] =
      //If the given is used, we already know that size > 0
      given (Finite.NotZero[Tuple.Size[T]] =:= true) = <:<.refl[Boolean].asInstanceOf[Finite.NotZero[Tuple.Size[T]] =:= true]
      val arr = IArray.tabulate(size.value)(i => f(Finite(size.value, i)))
      Tuple.fromIArray(arr).asInstanceOf[ProductK[A, T]]

    extension[A[_], C](fa: ProductK[A, T]) def indexK: RepresentationK ~>: A = 
      [Z] => (rep: RepresentationK[Z]) => fa.productElement(rep.value).asInstanceOf[A[Z]]

trait ProductKGather:
  self: ProductK.type =>
  inline given gatherImplicits[F[_], T <: Tuple]: ProductK[F, T] = self.of(summonAll[Tuple.Map[T, F]].asInstanceOf[Tuple.Map[T, F]])




© 2015 - 2025 Weber Informatics LLC | Privacy Policy