Skip to content

Commit

Permalink
Composed instances from cats, invariant and contravariant
Browse files Browse the repository at this point in the history
  • Loading branch information
Katrix committed Jan 5, 2024
1 parent d354335 commit 1da36c8
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ trait GenHKDGeneric[A]:
given TraverseKC[Gen] = traverse

export representable.*
export traverse.{asK => _, liftK => _, mapConst => _, mapK => _, voidK => _, widen => _, *}
export traverse.{asK => _, liftK => _, mapConst => _, mapK => _, voidK => _, widen => _, imapK => _, *}

// Cat generic functions

Expand Down
16 changes: 16 additions & 0 deletions dotty/perspective/src/main/scala/perspective/ApplicativeK.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package perspective

import cats.Applicative
import cats.syntax.all.*

/** A higher kinded [[cats.Applicative]] typeclass. */
trait ApplicativeK[F[_[_], _]] extends ApplyK[F]:
/** A higher kinded equivalent of [[cats.Applicative.pure]]. */
Expand All @@ -14,6 +17,19 @@ trait ApplicativeK[F[_[_], _]] extends ApplyK[F]:
object ApplicativeK:
given idInstanceC[A]: ApplicativeKC[IdFC[A]] = instances.idInstanceC[A]

given composeCats[F[_], G[_[_]]](using F: Applicative[F], G: ApplicativeKC[G]): ApplicativeKC[[H[_]] =>> F[G[H]]] with {
extension [A[_], C](fa: F[G[A]])
override def map2K[B[_], Z[_]](fb: F[G[B]])(f: [Y] => (A[Y], B[Y]) => Z[Y]): F[G[Z]] =
fa.map2(fb)((a, b) => a.map2K(b)(f))

override def mapK[B[_]](f: A :~>: B): F[G[B]] = fa.map(_.mapK(f))

extension [A[_]](a: ValueK[A])
override def pure[C]: F[G[A]] = F.pure(G.pure(a))
}

given composeId[F[_], X](using F: Applicative[F]): ApplicativeKC[[H[_]] =>> F[H[X]]] = composeCats[F, IdFC[X]]

/**
* A version of [[ApplicativeK]] without a normal type as well as a higher
* kinded type.
Expand Down
12 changes: 12 additions & 0 deletions dotty/perspective/src/main/scala/perspective/ApplyK.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package perspective

import cats.Apply
import cats.syntax.all.*

/** A higher kinded [[cats.Apply]] typeclass. */
trait ApplyK[F[_[_], _]] extends FunctorK[F]:
/** A higher kinded equivalent of [[cats.Apply.ap]]. */
Expand All @@ -22,6 +25,15 @@ trait ApplyK[F[_[_], _]] extends FunctorK[F]:
object ApplyK:
given idInstanceC[A]: ApplyKC[IdFC[A]] = instances.idInstanceC[A]

given composeCats[F[_], G[_[_]]](using F: Apply[F], G: ApplyKC[G]): ApplyKC[[H[_]] =>> F[G[H]]] with
extension [A[_], C](fa: F[G[A]])
override def map2K[B[_], Z[_]](fb: F[G[B]])(f: [Y] => (A[Y], B[Y]) => Z[Y]): F[G[Z]] =
fa.map2(fb)((a, b) => a.map2K(b)(f))

override def mapK[B[_]](f: A :~>: B): F[G[B]] = fa.map(_.mapK(f))

given composeId[F[_], X](using F: Apply[F]): ApplyKC[[H[_]] =>> F[H[X]]] = composeCats[F, IdFC[X]]

/**
* A version of [[ApplyK]] without a normal type as well as a higher kinded
* type.
Expand Down
20 changes: 20 additions & 0 deletions dotty/perspective/src/main/scala/perspective/ContravariantK.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package perspective

import cats.Contravariant
import cats.syntax.all.*

trait ContravariantK[F[_[_], _]] extends InvariantK[F]:
extension [A[_], C](fa: F[A, C])
/** A higher kinded equivalent of [[cats.Contravariant.contramap]]. */
def contramapK[B[_]](f: B :~>: A): F[B, C]

override def imapK[B[_]](f: A :~>: B)(g: B :~>: A): F[B, C] = contramapK(g)

object ContravariantK:
given composeCats[F[_], G[_[_]]](using F: Contravariant[F], G: FunctorKC[G]): ContravariantKC[[H[_]] =>> F[G[H]]] with
extension [A[_], C](fa: F[G[A]])
override def contramapK[B[_]](f: B :~>: A): F[G[B]] = fa.contramap(_.mapK(f))

given composeId[F[_], X](using F: Contravariant[F]): ContravariantKC[[H[_]] =>> F[H[X]]] = composeCats[F, IdFC[X]]

type ContravariantKC[F[_[_]]] = ContravariantK[IgnoreC[F]]
10 changes: 10 additions & 0 deletions dotty/perspective/src/main/scala/perspective/DistributiveK.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ trait DistributiveK[F[_[_], _]] extends FunctorK[F]:
object DistributiveK:
given idInstanceC[A]: DistributiveKC[IdFC[A]] = perspective.instances.idInstanceC[A]

given composeCats[F[_], G[_[_]]](using F: Distributive[F], G: DistributiveKC[G]): DistributiveKC[[H[_]] =>> F[G[H]]] with
extension [A[_], C](fa: F[G[A]])
override def mapK[B[_]](f: A :~>: B): F[G[B]] = fa.map(_.mapK(f))

extension [H[_] : Functor, A[_], C](gfa: H[F[G[A]]])
override def cosequenceK: F[G[Compose2[H, A]]] =
F.cosequence(gfa).map(v => G.cosequenceK(v))

given composeId[F[_], X](using F: Distributive[F]): DistributiveKC[[H[_]] =>> F[H[X]]] = composeCats[F, IdFC[X]]

/**
* A version of [[DistributiveK]] without a normal type as well as a higher
* kinded type.
Expand Down
13 changes: 12 additions & 1 deletion dotty/perspective/src/main/scala/perspective/FoldableK.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,19 @@ trait FoldableK[F[_[_], _]]:
extension [A, C](fa: F[Const[A], C])
def toListK: List[A] =
fa.foldMapK(FunctionK.liftConst(List(_: A)))

object FoldableK:
given idInstanceC[A]: FoldableKC[IdFC[A]] = perspective.instances.idInstanceC[A]

given composeCats[F[_], G[_[_]]](using F: Foldable[F], G: FoldableKC[G]): FoldableKC[[H[_]] =>> F[G[H]]] with {
extension [A[_], C](fa: F[G[A]])
override def foldLeftK[B](b: B)(f: B => A :~>#: B): B =
fa.foldLeft(b)((bacc, a) => a.foldLeftK(bacc)(f))

override def foldRightK[B](b: B)(f: A :~>#: (B => B)): B =
fa.foldRight(Eval.now(b))((a, bacce) => Eval.now(a.foldRightK(bacce.value)(f))).value
}

given composeId[F[_], X](using F: Foldable[F]): FoldableKC[[H[_]] =>> F[H[X]]] = composeCats[F, IdFC[X]]

type FoldableKC[F[_[_]]] = FoldableK[IgnoreC[F]]
19 changes: 15 additions & 4 deletions dotty/perspective/src/main/scala/perspective/FunctorK.scala
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package perspective

import scala.compiletime._
import scala.deriving._
import scala.quoted._
import cats.Functor
import cats.syntax.all.*

import scala.compiletime.*
import scala.deriving.*
import scala.quoted.*

/** A higher kinded [[cats.Functor]] typeclass. */
trait FunctorK[F[_[_], _]]:
trait FunctorK[F[_[_], _]] extends InvariantK[F]:
extension [A[_], C](fa: F[A, C])
/** A higher kinded equivalent of [[cats.Functor.map]]. */
def mapK[B[_]](f: A :~>: B): F[B, C]

override def imapK[B[_]](f: A :~>: B)(g: B :~>: A): F[B, C] = mapK(f)

/** Helper function that calls [[mapK]] with [[Const]]. */
inline def mapConst[B](f: A :~>#: B): F[Const[B], C] =
mapK(f)
Expand All @@ -30,6 +35,12 @@ trait FunctorK[F[_[_], _]]:
object FunctorK:
given idInstanceC[A]: FunctorKC[IdFC[A]] = instances.idInstanceC[A]

given composeCats[F[_], G[_[_]]](using F: Functor[F], G: FunctorKC[G]): FunctorKC[[H[_]] =>> F[G[H]]] with
extension [A[_], C](fa: F[G[A]])
override def mapK[B[_]](f: A :~>: B): F[G[B]] = fa.map(_.mapK(f))

given composeId[F[_], X](using F: Functor[F]): FunctorKC[[H[_]] =>> F[H[X]]] = composeCats[F, IdFC[X]]

/**
* A version of [[FunctorK]] without a normal type as well as a higher kinded
* type.
Expand Down
20 changes: 20 additions & 0 deletions dotty/perspective/src/main/scala/perspective/InvariantK.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package perspective

import cats.Invariant
import cats.syntax.all.*

trait InvariantK[F[_[_], _]]:
extension [A[_], C](fa: F[A, C])
/** A higher kinded equivalent of [[cats.Invariant.imap]]. */
def imapK[B[_]](f: A :~>: B)(g: B :~>: A): F[B, C]

object InvariantK:
given idInstanceC[A]: InvariantKC[IdFC[A]] = instances.idInstanceC[A]

given composeCats[F[_], G[_[_]]](using F: Invariant[F], G: InvariantKC[G]): InvariantKC[[H[_]] =>> F[G[H]]] with
extension [A[_], C](fa: F[G[A]])
override def imapK[B[_]](f: A :~>: B)(g: B :~>: A): F[G[B]] = fa.imap(_.imapK(f)(g))(_.imapK(g)(f))

given composeId[F[_], X](using F: Invariant[F]): InvariantKC[[H[_]] =>> F[H[X]]] = composeCats[F, IdFC[X]]

type InvariantKC[F[_[_]]] = InvariantK[IgnoreC[F]]
22 changes: 20 additions & 2 deletions dotty/perspective/src/main/scala/perspective/RepresentableK.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package perspective

import scala.language.implicitConversions

import cats.Functor
import cats.syntax.all._
import cats.syntax.all.*
import cats.{Functor, Representable}

/** A higher kinded [[cats.Representable]]. */
trait RepresentableK[F[_[_], _]] extends MonadK[F] with DistributiveK[F]:
Expand Down Expand Up @@ -57,3 +57,21 @@ object RepresentableKC:
type Aux[F[_[_]], RepresentationK0[_]] = RepresentableKC[F] {
type RepresentationK[A] = RepresentationK0[A]
}

given idInstanceC[A]: RepresentableKC.Aux[IdFC[A], [Z] =>> Finite[1]] = perspective.instances.idInstanceC[A]

given composeCats[F[_], G[_[_]], R1, R2[_]](
using F: Representable.Aux[F, R1],
G: RepresentableKC.Aux[G, R2]
): RepresentableKC.Aux[[H[_]] =>> F[G[H]], [X] =>> (R1, R2[X])] = new RepresentableKC[[H[_]] =>> F[G[H]]] {
override type RepresentationK[A] = (R1, R2[A])

extension [A[_], C](fa: F[G[A]])
override def indexK[Z](i: (R1, R2[Z])): A[Z] =
F.index(fa)(i._1).indexK(i._2)

override def tabulateK[A[_], C](f: RepresentationK :~>: A): F[G[A]] =
F.tabulate(r1 => G.tabulateK([X] => (r2: R2[X]) => f((r1, r2))))
}

given composeId[F[_], R1, X](using F: Representable.Aux[F, R1]): RepresentableKC[[H[_]] =>> F[H[X]]] = composeCats[F, IdFC[X], R1, [Z] =>> Finite[1]]
16 changes: 16 additions & 0 deletions dotty/perspective/src/main/scala/perspective/TraverseK.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ trait TraverseK[F[_[_], _]] extends FunctorK[F], FoldableK[F]:
object TraverseK:
given idInstanceC[A]: TraverseKC[IdFC[A]] = perspective.instances.idInstanceC[A]

given composeCats[F[_], G[_[_]]](using F: Traverse[F], G: TraverseKC[G]): TraverseKC[[H[_]] =>> F[G[H]]] with {
extension [A[_], C](fa: F[G[A]])
override def mapK[B[_]](f: A :~>: B): F[G[B]] = fa.map(_.mapK(f))

override def foldLeftK[B](b: B)(f: B => A :~>#: B): B =
fa.foldLeft(b)((bacc, a) => a.foldLeftK(bacc)(f))

override def foldRightK[B](b: B)(f: A :~>#: (B => B)): B =
fa.foldRight(Eval.now(b))((a, bacce) => Eval.now(a.foldRightK(bacce.value)(f))).value

override def traverseK[H[_]: Applicative, B[_]](f: A :~>: Compose2[H, B]): H[F[G[B]]] =
fa.traverse(_.traverseK(f))
}

given composeId[F[_], X](using F: Traverse[F]): TraverseKC[[H[_]] =>> F[H[X]]] = composeCats[F, IdFC[X]]

/**
* A version of [[TraverseK]] without a normal type as well as a higher kinded
* type.
Expand Down

0 comments on commit 1da36c8

Please sign in to comment.